diff options
| author | gingerBill <bill@gingerbill.org> | 2025-03-24 13:11:41 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2025-03-24 13:11:41 +0000 |
| commit | 56e0ab7655337b8ce9738d214c21e5f06e91df09 (patch) | |
| tree | 358f30b442ca2cdb4af8b1a9866220d2fb3fc0f5 /src/llvm_backend_const.cpp | |
| parent | acb578f184c55f0d1b20ef844a506185684efeba (diff) | |
Fix #4952
Diffstat (limited to 'src/llvm_backend_const.cpp')
| -rw-r--r-- | src/llvm_backend_const.cpp | 49 |
1 files changed, 44 insertions, 5 deletions
diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index b916c0017..c011e62f4 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1125,10 +1125,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo visited[index] = true; } else { if (!visited[index]) { - values[index] = lb_const_value(m, f->type, {}, false).value; + values[index] = lb_const_value(m, f->type, {}, allow_local, is_rodata).value; visited[index] = true; } + unsigned idx_list_len = cast(unsigned)sel.index.count-1; unsigned *idx_list = gb_alloc_array(temporary_allocator(), unsigned, idx_list_len); @@ -1139,6 +1140,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i32 index = sel.index[j]; Type *cvt = base_type(cv_type); + if (cvt->kind == Type_Struct) { if (cvt->Struct.is_raw_union) { // sanity check which should have been caught by `lb_is_nested_possibly_constant` @@ -1164,9 +1166,38 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } if (is_constant) { LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local, is_rodata).value; - if (LLVMIsConstant(elem_value)) { + if (LLVMIsConstant(elem_value) && LLVMIsConstant(values[index])) { values[index] = llvm_const_insert_value(m, values[index], elem_value, idx_list, idx_list_len); - } else { + } else if (is_local) { + lbProcedure *p = m->curr_procedure; + GB_ASSERT(p != nullptr); + if (LLVMIsConstant(values[index])) { + lbAddr addr = lb_add_local_generated(p, f->type, false); + lb_addr_store(p, addr, lbValue{values[index], f->type}); + values[index] = lb_addr_load(p, addr).value; + } + + GB_ASSERT(LLVMIsALoadInst(values[index])); + + LLVMValueRef ptr = LLVMGetOperand(values[index], 0); + + LLVMValueRef *indices = gb_alloc_array(temporary_allocator(), LLVMValueRef, idx_list_len); + LLVMTypeRef lt_u32 = lb_type(m, t_u32); + for (unsigned i = 0; i < idx_list_len; i++) { + indices[i] = LLVMConstInt(lt_u32, idx_list[i], false); + } + + ptr = LLVMBuildGEP2(p->builder, lb_type(m, f->type), ptr, indices, idx_list_len, ""); + ptr = LLVMBuildPointerCast(p->builder, ptr, lb_type(m, alloc_type_pointer(tav.type)), ""); + + if (LLVMIsALoadInst(elem_value)) { + i64 sz = type_size_of(tav.type); + LLVMValueRef src = LLVMGetOperand(elem_value, 0); + lb_mem_copy_non_overlapping(p, {ptr, t_rawptr}, {src, t_rawptr}, lb_const_int(m, t_int, sz), false); + } else { + LLVMBuildStore(p->builder, elem_value, ptr); + } + is_constant = false; } } @@ -1205,7 +1236,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef val = values[i]; if (!LLVMIsConstant(val)) { GB_ASSERT(is_local); - GB_ASSERT(LLVMGetInstructionOpcode(val) == LLVMLoad); + GB_ASSERT(LLVMIsALoadInst(val)); is_constant = false; } } @@ -1237,7 +1268,15 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef val = old_values[i]; if (!LLVMIsConstant(val)) { LLVMValueRef dst = LLVMBuildStructGEP2(p->builder, llvm_addr_type(p->module, v.addr), v.addr.value, cast(unsigned)i, ""); - LLVMBuildStore(p->builder, val, dst); + if (LLVMIsALoadInst(val)) { + Type *ptr_type = v.addr.type; + i64 sz = type_size_of(type_deref(ptr_type)); + + LLVMValueRef src = LLVMGetOperand(val, 0); + lb_mem_copy_non_overlapping(p, {dst, ptr_type}, {src, ptr_type}, lb_const_int(m, t_int, sz), false); + } else { + LLVMBuildStore(p->builder, val, dst); + } } } return lb_addr_load(p, v); |