result loc semantics for loading packed struct pointer to packed struct

```zig
export fn entry() void {
    var x = foo();
    var ptr = &x.b;
    var y = ptr.*;
}
const Foo = packed struct {
    a: u24 = 1,
    b: Bar = Bar{},
};

const Bar = packed struct {
    a: u4 = 2,
    b: u4 = 3,
};
```

```llvm
define void @entry() #2 !dbg !35 {
Entry:
  %x = alloca %Foo, align 1
  %ptr = alloca i32*, align 8
  %y = alloca %Bar, align 1
  call fastcc void @foo(%Foo* sret %x), !dbg !55
  call void @llvm.dbg.declare(metadata %Foo* %x, metadata !39, metadata !DIExpression()), !dbg !56
  %0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0, !dbg !57
  store i32* %0, i32** %ptr, align 8, !dbg !57
  call void @llvm.dbg.declare(metadata i32** %ptr, metadata !51, metadata !DIExpression()), !dbg !58
  %1 = load i32*, i32** %ptr, align 8, !dbg !59
  %2 = load i32, i32* %1, align 1, !dbg !60
  %3 = lshr i32 %2, 24, !dbg !60
  %4 = trunc i32 %3 to i8, !dbg !60
  %5 = bitcast %Bar* %y to i8*, !dbg !60
  store i8 %4, i8* %5, !dbg !60
  call void @llvm.dbg.declare(metadata %Bar* %y, metadata !54, metadata !DIExpression()), !dbg !61
  ret void, !dbg !62
}
```
This commit is contained in:
Andrew Kelley 2019-06-10 19:11:34 -04:00
parent 65f6ea66f4
commit 9a324ecb42
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
4 changed files with 92 additions and 75 deletions

View File

@ -2449,8 +2449,9 @@ struct IrInstructionUnOp {
IrInstruction base;
IrUnOp op_id;
IrInstruction *value;
LVal lval;
IrInstruction *value;
ResultLoc *result_loc;
};
enum IrBinOp {
@ -2507,7 +2508,7 @@ struct IrInstructionLoadPtrGen {
IrInstruction base;
IrInstruction *ptr;
LLVMValueRef tmp_ptr;
IrInstruction *result_loc;
};
struct IrInstructionStorePtr {

View File

@ -3376,13 +3376,13 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
if (handle_is_ptr(child_type)) {
assert(instruction->tmp_ptr != nullptr);
LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");
LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr,
LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, result_loc,
LLVMPointerType(same_size_int, 0), "");
LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr);
return instruction->tmp_ptr;
return result_loc;
}
if (child_type->id == ZigTypeIdFloat) {
@ -6838,9 +6838,6 @@ static void do_code_gen(CodeGen *g) {
slot = &ref_instruction->tmp_ptr;
assert(instruction->value.type->id == ZigTypeIdPointer);
slot_type = instruction->value.type->data.pointer.child_type;
} else if (instruction->id == IrInstructionIdLoadPtrGen) {
IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction;
slot = &load_ptr_inst->tmp_ptr;
} else if (instruction->id == IrInstructionIdVectorToArray) {
IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction;
alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type);

View File

@ -161,7 +161,8 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
ResultLoc *result_loc);
static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type);
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr);
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr,
ResultLoc *result_loc);
static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg);
static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing);
@ -1467,12 +1468,13 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s
}
static IrInstruction *ir_build_un_op_lval(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id,
IrInstruction *value, LVal lval)
IrInstruction *value, LVal lval, ResultLoc *result_loc)
{
IrInstructionUnOp *instruction = ir_build_instruction<IrInstructionUnOp>(irb, scope, source_node);
instruction->op_id = op_id;
instruction->value = value;
instruction->lval = lval;
instruction->result_loc = result_loc;
ir_ref_instruction(value, irb->current_basic_block);
@ -1482,7 +1484,7 @@ static IrInstruction *ir_build_un_op_lval(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id,
IrInstruction *value)
{
return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone);
return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone, nullptr);
}
static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node,
@ -2471,14 +2473,16 @@ static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *sourc
}
static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *source_instruction,
IrInstruction *ptr, ZigType *ty)
IrInstruction *ptr, ZigType *ty, IrInstruction *result_loc)
{
IrInstructionLoadPtrGen *instruction = ir_build_instruction<IrInstructionLoadPtrGen>(
&ira->new_irb, source_instruction->scope, source_instruction->source_node);
instruction->base.value.type = ty;
instruction->ptr = ptr;
instruction->result_loc = result_loc;
ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
return &instruction->base;
}
@ -8028,7 +8032,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
// We essentially just converted any lvalue from &(x.*) to (&x).*;
// this inhibits checking that x is a pointer later, so we directly
// record whether the pointer check is needed
return ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval);
IrInstruction *un_op = ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval, result_loc);
return ir_expr_wrap(irb, scope, un_op, result_loc);
}
case NodeTypeUnwrapOptional: {
AstNode *expr_node = node->data.unwrap_optional.expr;
@ -11312,7 +11317,7 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
IrInstruction *array_ptr = nullptr;
IrInstruction *array;
if (array_arg->value.type->id == ZigTypeIdPointer) {
array = ir_get_deref(ira, source_instr, array_arg);
array = ir_get_deref(ira, source_instr, array_arg, nullptr);
array_ptr = array_arg;
} else {
array = array_arg;
@ -12512,60 +12517,71 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig
return ir_implicit_cast_with_result(ira, value, expected_type, nullptr);
}
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr,
ResultLoc *result_loc)
{
Error err;
ZigType *type_entry = ptr->value.type;
if (type_is_invalid(type_entry)) {
if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
} else if (type_entry->id == ZigTypeIdPointer) {
ZigType *child_type = type_entry->data.pointer.child_type;
// if the child type has one possible value, the deref is comptime
switch (type_has_one_possible_value(ira->codegen, child_type)) {
case OnePossibleValueInvalid:
return ira->codegen->invalid_instruction;
case OnePossibleValueYes:
return ir_const(ira, source_instruction, child_type);
case OnePossibleValueNo:
break;
}
if (instr_is_comptime(ptr)) {
if (ptr->value.special == ConstValSpecialUndef) {
ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value"));
return ira->codegen->invalid_instruction;
}
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst ||
ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
{
ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
if (pointee->special != ConstValSpecialRuntime) {
IrInstruction *result = ir_const(ira, source_instruction, child_type);
if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value,
&ptr->value)))
{
return ira->codegen->invalid_instruction;
}
result->value.type = child_type;
return result;
}
}
}
// if the instruction is a const ref instruction we can skip it
if (ptr->id == IrInstructionIdRef) {
IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);
return ref_inst->value;
}
IrInstruction *result = ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type);
if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
ir_add_alloca(ira, result, child_type);
}
return result;
} else {
if (type_entry->id != ZigTypeIdPointer) {
ir_add_error_node(ira, source_instruction->source_node,
buf_sprintf("attempt to dereference non-pointer type '%s'",
buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
}
ZigType *child_type = type_entry->data.pointer.child_type;
// if the child type has one possible value, the deref is comptime
switch (type_has_one_possible_value(ira->codegen, child_type)) {
case OnePossibleValueInvalid:
return ira->codegen->invalid_instruction;
case OnePossibleValueYes:
return ir_const(ira, source_instruction, child_type);
case OnePossibleValueNo:
break;
}
if (instr_is_comptime(ptr)) {
if (ptr->value.special == ConstValSpecialUndef) {
ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value"));
return ira->codegen->invalid_instruction;
}
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst ||
ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
{
ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
if (pointee->special != ConstValSpecialRuntime) {
IrInstruction *result = ir_const(ira, source_instruction, child_type);
if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value,
&ptr->value)))
{
return ira->codegen->invalid_instruction;
}
result->value.type = child_type;
return result;
}
}
}
// if the instruction is a const ref instruction we can skip it
if (ptr->id == IrInstructionIdRef) {
IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);
return ref_inst->value;
}
IrInstruction *result_loc_inst;
if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
if (result_loc == nullptr) result_loc = no_result_loc();
result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr);
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
return result_loc_inst;
}
} else {
result_loc_inst = nullptr;
}
return ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type, result_loc_inst);
}
static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) {
@ -14585,7 +14601,7 @@ IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_i
ZigVar *coro_allocator_var = ira->old_irb.exec->coro_allocator_var;
assert(coro_allocator_var != nullptr);
IrInstruction *var_ptr_inst = ir_get_var_ptr(ira, source_instr, coro_allocator_var);
IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst);
IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst, nullptr);
assert(result->value.type != nullptr);
return result;
}
@ -15313,7 +15329,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
first_arg = first_arg_ptr;
} else {
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr);
if (type_is_invalid(first_arg->value.type))
return ira->codegen->invalid_instruction;
}
@ -15472,7 +15488,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
first_arg = first_arg_ptr;
} else {
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr);
if (type_is_invalid(first_arg->value.type))
return ira->codegen->invalid_instruction;
}
@ -15516,7 +15532,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
if (type_is_invalid(arg_var_ptr_inst->value.type))
return ira->codegen->invalid_instruction;
IrInstruction *arg_tuple_arg = ir_get_deref(ira, arg, arg_var_ptr_inst);
IrInstruction *arg_tuple_arg = ir_get_deref(ira, arg, arg_var_ptr_inst, nullptr);
if (type_is_invalid(arg_tuple_arg->value.type))
return ira->codegen->invalid_instruction;
@ -15702,7 +15718,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
{
first_arg = first_arg_ptr;
} else {
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr);
if (type_is_invalid(first_arg->value.type))
return ira->codegen->invalid_instruction;
}
@ -16113,7 +16129,7 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction
return ira->codegen->invalid_instruction;
}
IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr);
IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr, instruction->result_loc);
if (result == ira->codegen->invalid_instruction)
return ira->codegen->invalid_instruction;
@ -16994,7 +17010,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
assert(container_ptr->value.type->id == ZigTypeIdPointer);
if (container_type->id == ZigTypeIdPointer) {
ZigType *bare_type = container_ref_type(container_type);
IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr);
IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr, nullptr);
IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type, field_ptr_instruction->initializing);
return result;
} else {
@ -17339,7 +17355,7 @@ static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruct
IrInstruction *ptr = instruction->ptr->child;
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
return ir_get_deref(ira, &instruction->base, ptr);
return ir_get_deref(ira, &instruction->base, ptr, nullptr);
}
static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
@ -17807,7 +17823,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
}
if (!safety_check_on)
return base_ptr;
IrInstruction *c_ptr_val = ir_get_deref(ira, source_instr, base_ptr);
IrInstruction *c_ptr_val = ir_get_deref(ira, source_instr, base_ptr, nullptr);
ir_build_assert_non_null(ira, source_instr, c_ptr_val);
return base_ptr;
}
@ -18162,7 +18178,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr);
result->value.type = target_type;
return result;
}
@ -18192,7 +18208,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr);
union_value->value.type = target_type;
IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope,
@ -18216,7 +18232,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr);
enum_value->value.type = target_type;
return enum_value;
}
@ -23105,7 +23121,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
if (lval == LValPtr) {
return var_ptr;
} else {
return ir_get_deref(ira, &instruction->base, var_ptr);
return ir_get_deref(ira, &instruction->base, var_ptr, nullptr);
}
}
case TldIdFn: {
@ -23640,7 +23656,7 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr
}
if (instr_is_comptime(casted_ptr)) {
IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr);
IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr, nullptr);
ir_assert(result->value.type != nullptr, &instruction->base);
return result;
}
@ -24474,7 +24490,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdUnOp:
case IrInstructionIdBinOp:
case IrInstructionIdLoadPtr:
case IrInstructionIdLoadPtrGen:
case IrInstructionIdConst:
case IrInstructionIdCast:
case IrInstructionIdContainerInitList:
@ -24585,6 +24600,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
return reinterpret_cast<IrInstructionErrWrapPayload *>(instruction)->result_loc != nullptr;
case IrInstructionIdErrWrapCode:
return reinterpret_cast<IrInstructionErrWrapCode *>(instruction)->result_loc != nullptr;
case IrInstructionIdLoadPtrGen:
return reinterpret_cast<IrInstructionLoadPtrGen *>(instruction)->result_loc != nullptr;
}
zig_unreachable();
}

View File

@ -397,8 +397,10 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
}
static void ir_print_load_ptr_gen(IrPrint *irp, IrInstructionLoadPtrGen *instruction) {
fprintf(irp->f, "loadptr(");
ir_print_other_instruction(irp, instruction->ptr);
fprintf(irp->f, ".*");
fprintf(irp->f, ")result=");
ir_print_other_instruction(irp, instruction->result_loc);
}
static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {