← 12套面试训练

LOOP 11 / INTERVIEW LOOP / 4H

编译器面试:活跃区间与优化合法性

编译器要把三个临时张量放进尽量少的存储槽。你必须明确值何时仍会被读取;随后面试官要求重排浮点表达式,检查你是否把内存优化和数值语义混在一起。

完成单元 73 · 把编译器责任接回同一主项目及其先备后安排本次训练。不绑定日历周。

先写自己的答案,再展开参考。这里按技能编写问题,不声称公司真题;自评与阅读都不会自动通过 G0。

先备与学习位置

回到对应的路线里程碑 →

TIME WITH OUTPUTS

240 分钟怎样用

  1. 闭卷恢复先备 · 15min

    说明 SSA 值名、最后使用、别名、ABI 的各自含义;回忆真实 Clang 实验只证明它实际执行过的输入和工具行为。

    留下:先不查章节,写三条判断和一个不确定点;再只补读相关章节的解释段。

  2. 澄清题目与手算 · 25min

    读主问题,逐条写输入、输出、范围与失败行为。手算前两个公开用例,给自己的方案找一个反例。

    留下:一份接口合同、逐步状态表和最小反例;不要先打开参考推演。

  3. 独立实现或设计 · 55min

    设计并实现一个小的 slot-assignment 验证器:输入 A=[0,2)、B=[1,3)、C=[2,4) 三个已给定活跃区间和每个值的槽号。只有大小、类型、对齐都相同的值才可考虑复用;本题假定这些条件满足。两个半开区间重叠且槽号相同则拒绝。验证 [0,1,0] 与 [0,0,1];然后把 A 延长到 [0,3) 重新判断。

    留下:保存个人代码或设计稿。编码题保留编译命令;设计题为每个事件编号,不能只画没有状态的箭头。

  4. 边界与反证 · 25min

    用题目的全部公开用例核对真实输出;另外创造一个与公开输入不同的边界。发现失败时缩小输入,再解释修复。

    留下:实际结果、原始失败和修复原因各一份;设计题记录一个被拒绝的执行顺序。

  5. 按表现进入追问树 · 35min

    从 n1 开始。每题先录下自己的回答,再展开标准;按满足或未满足条件跳转。树最多走一轮,卡住时把剩余时间用于分支中的纠错,不循环加时。

    留下:记录经过的节点、原话、缺失条件和修订;只会复述标准的节点仍标记待重做。

  6. 英文口述与打断 · 30min

    用本页英文提纲录制两轮 90 秒回答;第二轮在 30 秒处自问追问,先回答追问再回到主线。每轮回听并改写两个含糊句。

    留下:两轮录音或逐字稿;圈出输入、因果、边界和限制各一句。参考英文在录完第一轮后再读。

  7. 复盘与安排重做 · 25min

    对照强弱答案,选择一个真正出错的环节:合同、状态、实现、验证或表达。填本页记录模板,并约定下一天的 30 分钟。

    留下:一个有失败输入的错误记录和一个可观察修复标准;不要把全部问题归因为粗心。

  8. 次日无答案重做 · 30min

    次日使用 X=[0,1)、Y=[1,2)、Z=[0,2)。独立验证 slots=[0,0,1] 与 [0,1,0],给出最少槽数及理由;再将 Y.start 改为 0 重评第一份分配。

    留下:这是本周 240 分钟中的最后 30 分钟,不另加预算。先关闭解答,用 20 分钟独立做,再用 10 分钟核验并记录是否仍需复习。

包括次日重做,总计 240min。局部错因复盘属于本次练习,额外的计划复盘按实际需要另记。

SOLVE BEFORE READING THE ANSWER

先独立处理这个问题

设计并实现一个小的 slot-assignment 验证器:输入 A=[0,2)、B=[1,3)、C=[2,4) 三个已给定活跃区间和每个值的槽号。只有大小、类型、对齐都相同的值才可考虑复用;本题假定这些条件满足。两个半开区间重叠且槽号相同则拒绝。验证 [0,1,0] 与 [0,0,1];然后把 A 延长到 [0,3) 重新判断。

输入与输出合同

  • 区间来自本题给定的合法顺序;不要求你从真实 IR 完整推导 alias/liveness。
  • 相邻两个区间中,前段的 end 等于后段的 start 时视为不重叠;每个槽号为非负整数。
  • 验证器须逐对检查,不能只打印“slots=2”;槽数量由真实使用的不同槽号计算。
  • 每个区间必须满足 start<end,槽号列表长度必须等于区间数量;任一不满足就显式拒绝。空区间集合合法,不等于允许单个零长度区间。
手算之后,对照公开用例
输入或情形预期为什么
A[0,2),B[1,3),C[2,4),slots=[0,1,0]接受;使用 2 个槽A/C 不重叠且其他重叠对不同槽。
原区间,slots=[0,0,1]拒绝A/B 同槽且重叠。
A 延长到[0,3),其余不变,slots=[0,1,0]拒绝A/C 在 [2,3) 重叠。
延长后的区间,slots=[0,1,2]接受;使用 3 个槽t=2 时三个值同时活跃,三槽也确实必要。
区间集合为空,槽号列表为空接受;0 个槽没有值需要存储。
区间=[[2,2)],slots=[0]拒绝非法区间单个区间必须 start<end。
原三个区间,slots=[0,1]拒绝长度不匹配不能读取不存在的第三个槽号。

先保留自己的解法、状态轨迹与验证记录,再打开参考。允许用自然语言或伪代码补充解释;不能用参考输出代替真实运行。

保存独立尝试后,阅读解法与状态轨迹

解法依据

先检查区间与槽列表等长、每个 start<end、所有槽号非负;不满足就拒绝,再进行配对检查。对于每一对 i<j,重叠条件是 start_i<end_j 且 start_j<end_i;若重叠又同槽就拒绝。原分配中只有 A/C 共用槽0,而 [0,2) 与 [2,4) 不重叠,所以可用两槽。延长 A 后,A/B/C 在 [2,3) 同时活跃,任何两者都不能同槽,需要至少三槽。现实编译器还要证明别名、异步消费者、尺寸、对齐与副作用,本题只验证已给区间合同。

逐步推演

原题 t=1:A/B 活跃,分别槽0/1;t=2:A 已结束、B/C 活跃,C 才能复用槽0。延长后 t=2:A/B/C 同时活跃,旧槽0 同时分给 A/C,拒绝。这个反例不是改打印文字可以修复的。

FOLLOW THE ANSWER, NOT A SCRIPT

从回答进入下一层追问

n1 开始。先录下回答,再展开判定;达到条件就走深入分支,未达到就按反馈缩小问题。一次最多走一轮,不靠反复查看同一答案累积“通过”。

把实际走过的节点记入模板 →

NODE n1

为什么 end==start 可以复用,而 start 相同通常不能?

我已作答:查看判定与下一分支

需要解释清楚:半开合同意味着前一个值在 end 时不再活跃;相同 start 且非空区间会同时需要存储。

达到

结论正确,并解释本节点给出的具体状态或反例。

保留关键推理:半开合同意味着前一个值在 end 时不再活跃;相同 start 且非空区间会同时需要存储。

继续到 n2 →

待补

只报术语、漏掉条件,或不能解释题中的数值。

分别画 [0,2)/[2,4) 和 [0,2)/[0,4),在 t=1、2 标出活跃集合。

继续到 r1 →

NODE r1

把第一个追问缩到最小输入,重新逐步说明。

我已作答:查看判定与下一分支

需要解释清楚:半开合同意味着前一个值在 end 时不再活跃;相同 start 且非空区间会同时需要存储。

修复后达到

用具体输入改正原回答,能指出之前错在哪里。

分别画 [0,2)/[2,4) 和 [0,2)/[0,4),在 t=1、2 标出活跃集合。

继续到 n2 →

仍未达到

仍依赖答案复述,不能独立重建状态。

本次树到此结束;把 n1 的输入和缺口写入复盘,再进入英文练习与次日重做。

这一分支结束:对照并复盘 →

NODE n2

若异步消费者直到 t=5 才读完 A,还能用原 A.end=2 吗?

我已作答:查看判定与下一分支

需要解释清楚:不能,活跃结束应包含最后实际消费者;先前区间输入失真,验证器对错误区间通过也不能证明真实复用合法。

达到

结论正确,并解释本节点给出的具体状态或反例。

保留关键推理:不能,活跃结束应包含最后实际消费者;先前区间输入失真,验证器对错误区间通过也不能证明真实复用合法。

继续到 n3 →

待补

只报术语、漏掉条件,或不能解释题中的数值。

把 A 的最后消费者画到 t=5,再重新运行逐对冲突检查。

继续到 n3 →

NODE n3

可以无条件把 (a+b)+c 改成 a+(b+c) 吗?给出浮点反例。

我已作答:查看判定与下一分支

需要解释清楚:不可以。以常见 IEEE 浮点舍入的 a=1e20,b=-1e20,c=3 为例,左边可为 3,右边可为 0;必须说明类型、舍入与优化允许的语义。

达到

结论正确,并解释本节点给出的具体状态或反例。

保留关键推理:不可以。以常见 IEEE 浮点舍入的 a=1e20,b=-1e20,c=3 为例,左边可为 3,右边可为 0;必须说明类型、舍入与优化允许的语义。

这一分支结束:对照并复盘 →

待补

只报术语、漏掉条件,或不能解释题中的数值。

先算 a+b 抵消,再算 b+c 中小数被舍入丢失;将“实数代数成立”与“机器浮点保证”分开。

这一分支结束:对照并复盘 →

答案强在哪里,弱在哪里

保存自己的回答后,打开对照

弱答案

“A 和 C 名字不同,直接复用;O2 会保证结果不变。”

强答案

“我根据最后使用时间判断复用,半开区间相接才允许共享。A 延长后出现三值同时活跃,必须改变实际分配并逐对验证。优化合法性还取决于语言语义、别名和目标条件,不能从优化级别推断。”

强答案使用区间推理和可执行拒绝条件,明确了这个小验证器覆盖的边界。编译器名词并不能代替 liveness 或数值正确性证明。

在自己的原回答里划出一个缺失的条件或错误推理,再重说一遍。完整句子背熟,不代表能处理新约束。

ANSWER, THEN HANDLE AN INTERRUPTION

英文口述与打断

Explain a memory reuse decision and its assumptions.

  1. Define a half-open lifetime interval.
  2. Show the rejected overlap.
  3. Separate a model proof from real IR analysis.

“What if a device still reads A after the host has moved on?”

录完第一轮后,读英文示范
I allow two values to share a slot only when their lifetime intervals do not overlap and their storage requirements match. Extending A makes it overlap with C, so the old assignment must be rejected. My checker validates the supplied intervals; it does not prove that those intervals correctly describe aliases or asynchronous consumers in a real program.
  • 前 15 秒说明输入、输出和一个关键约定。
  • 至少用一个本题的数值解释因果,不只罗列英文术语。
  • 明确一个边界或尚未验证的限制;不能把教学推演说成项目经验。

次日关掉解答,换一个问题

次日使用 X=[0,1)、Y=[1,2)、Z=[0,2)。独立验证 slots=[0,0,1] 与 [0,1,0],给出最少槽数及理由;再将 Y.start 改为 0 重评第一份分配。

独立重做后核对

原题 [0,0,1] 接受、2槽;[0,1,0] 拒绝 X/Z;最少2,因为 Z 与 X/Y 任一同时活跃。Y.start=0 后第一份也拒绝 X/Y,此时三个值在 [0,1) 同时活跃,需3槽。

  • 关闭主问题答案并使用新输入独立完成。
  • 给出结果与原因;失败时记录最小反例,不能只把完成标记改成通过。

重做的 30min 已计入本套4h;需要更多补课时记录实际用时,按缺口顺延。

记录实际回答与证据

本次面试练习模板
# W11 算法 / 英文训练记录(仅个人练习,不是能力认证)
日期:
本次先备与尚不确定点:
主问题接口合同:
我最初的方案与状态表:
运行命令或设计事件编号:
失败输入 / 预期 / 实际:
修复与理由:
追问路径(节点 → 自己原话 → 缺口):
英文第一轮两处含糊句:
英文第二轮修订:
次日重做日期(30 分钟已含本周预算):
重做输入 / 实际结果 / 解释:
仍需补练:

本次练习的检查依据

验证器实际接受/拒绝候选,槽计数来自分配;能指出不真实的生命周期输入与浮点重排风险;不声称实现了完整编译器 pass。

模板在你的个人笔记中填写。网页只提供空模板;不会把这次训练写成项目经验或学习验收结果。