fix(compiler): for x in ptr/数组 实现解引用为空终止(指针/浮点元素支持 + 数组长度上限+NULL终止)
This commit is contained in:
1 parent
d14415a4e6
commit
9b46e1da78
1 file changed
+55
-11
@@ -1781,10 +1781,13 @@ class StmtGenCifMixin:
|
||||
if arr_v2 is not None:
|
||||
return self._handle_array_iter(trans, for_node, var_name, arr_v2)
|
||||
|
||||
# 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符)
|
||||
# 元素类型决定"空值"判定(用户语义:解引用后为空即终止):
|
||||
# 整数 → ==0;指针(如 i8** 遍历的元素 i8*)→ ==null;浮点 → ==0.0
|
||||
elem_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty)
|
||||
if elem_bits == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符")
|
||||
elem_is_ptr2: int = self.Gen.ExprGenBase.is_ptr_type(elem_ty)
|
||||
elem_fbits2: int = self.Gen.ExprGenBase.get_llvm_float_bits(elem_ty)
|
||||
if elem_bits == 0 and elem_is_ptr2 == 0 and elem_fbits2 == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 元素类型不是整数/指针/浮点,无法检查空终止符")
|
||||
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
|
||||
@@ -1822,15 +1825,26 @@ class StmtGenCifMixin:
|
||||
# 跳转到 cond
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# cond 块: load index, GEP, load elem, icmp eq 0
|
||||
# cond 块: load index, GEP, load elem, 空值判定(整数==0 / 指针==null / 浮点==0.0)
|
||||
llvmlite.position_at_end(builder, cond_bb)
|
||||
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca)
|
||||
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||||
builder, elem_ty, ptr_val, cur_idx)
|
||||
cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr)
|
||||
null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0)
|
||||
is_null: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_EQ, cur_elem, null_val)
|
||||
is_null: llvmlite.Value | t.CPtr = None
|
||||
if elem_is_ptr2 != 0:
|
||||
null_p: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, elem_ty, "null")
|
||||
if null_p is not None:
|
||||
is_null = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_p)
|
||||
elif elem_fbits2 != 0:
|
||||
zero_f2: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, elem_ty, 0.0)
|
||||
if zero_f2 is not None:
|
||||
is_null = llvmlite.build_fcmp(builder, llvmlite.FCMP_OEQ, cur_elem, zero_f2)
|
||||
else:
|
||||
null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0)
|
||||
is_null = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_val)
|
||||
if is_null is None:
|
||||
is_null = llvmlite.const_int(pool, 1, 0)
|
||||
llvmlite.build_cond_br(builder, is_null, end_bb, body_bb)
|
||||
|
||||
# body 块: store elem to var, 翻译循环体
|
||||
@@ -1947,6 +1961,9 @@ class StmtGenCifMixin:
|
||||
viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt)
|
||||
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "arr.elem.%d", cnt)
|
||||
elem_check_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "arr.body.%d", cnt)
|
||||
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
@@ -1958,19 +1975,46 @@ class StmtGenCifMixin:
|
||||
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# cond 块: load index, icmp slt idx, elem_count
|
||||
# cond 块: 先查越界(idx < count,越界时不能 GEP+load 判空)
|
||||
llvmlite.position_at_end(builder, cond_bb)
|
||||
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca)
|
||||
count_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, elem_count)
|
||||
in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_SLT, cur_idx, count_val)
|
||||
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
|
||||
llvmlite.build_cond_br(builder, in_bounds, elem_check_bb, end_bb)
|
||||
|
||||
# body 块: GEP(0, idx) → load elem → store to var → 循环体
|
||||
llvmlite.position_at_end(builder, body_bb)
|
||||
# elem_check 块: GEP(0, idx) → load elem → 空值判定(NULL 终止)
|
||||
# 用户语义:整数/指针/浮点元素按"解引用为空"提前终止(如 split 尾哨兵
|
||||
# 的 str 数组),同时保留长度上限防越界读;聚合元素只按长度迭代。
|
||||
llvmlite.position_at_end(builder, elem_check_bb)
|
||||
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||||
builder, arr_ty, elem_ty, arr_tmp, cur_idx)
|
||||
cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr)
|
||||
elem_bits_a: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty)
|
||||
elem_ptr_a: int = self.Gen.ExprGenBase.is_ptr_type(elem_ty)
|
||||
elem_fbits_a: int = self.Gen.ExprGenBase.get_llvm_float_bits(elem_ty)
|
||||
if elem_bits_a != 0 or elem_ptr_a != 0 or elem_fbits_a != 0:
|
||||
is_empty_a: llvmlite.Value | t.CPtr = None
|
||||
if elem_ptr_a != 0:
|
||||
null_ap: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, elem_ty, "null")
|
||||
if null_ap is not None:
|
||||
is_empty_a = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_ap)
|
||||
elif elem_fbits_a != 0:
|
||||
zero_af: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, elem_ty, 0.0)
|
||||
if zero_af is not None:
|
||||
is_empty_a = llvmlite.build_fcmp(builder, llvmlite.FCMP_OEQ, cur_elem, zero_af)
|
||||
else:
|
||||
zero_ai: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits_a, 0)
|
||||
is_empty_a = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, zero_ai)
|
||||
if is_empty_a is not None:
|
||||
llvmlite.build_cond_br(builder, is_empty_a, end_bb, body_bb)
|
||||
else:
|
||||
llvmlite.build_br(builder, body_bb)
|
||||
else:
|
||||
llvmlite.build_br(builder, body_bb)
|
||||
|
||||
# body 块: store elem to var → 循环体
|
||||
llvmlite.position_at_end(builder, body_bb)
|
||||
llvmlite.build_store(builder, cur_elem, var_alloca)
|
||||
|
||||
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
|
||||
|
||||
Reference in new issue
Block a user