result location semantics for @bitCast
```zig export fn entry() void { var x = @bitCast(f32, foo()); } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %x = alloca float, align 4 %0 = bitcast float* %x to %Foo*, !dbg !42 call fastcc void @foo(%Foo* sret %0), !dbg !42 call void @llvm.dbg.declare(metadata float* %x, metadata !39, metadata !DIExpression()), !dbg !43 ret void, !dbg !44 } ```
This commit is contained in:
parent
1a51bf6304
commit
17b1ac5d03
|
@ -1,8 +1,6 @@
|
|||
Scratch pad for stuff to do before merging master
|
||||
=================================================
|
||||
|
||||
* bitCast
|
||||
|
||||
look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated
|
||||
return ir_gen_comptime(irb, scope, node, lval);
|
||||
|
||||
|
@ -23,3 +21,5 @@ inferred comptime
|
|||
return ir_build_ref(irb, scope, value->source_node, value, false, false);
|
||||
|
||||
handle if with no else
|
||||
|
||||
|
||||
|
|
|
@ -2267,7 +2267,6 @@ enum IrInstructionId {
|
|||
IrInstructionIdTestComptime,
|
||||
IrInstructionIdPtrCastSrc,
|
||||
IrInstructionIdPtrCastGen,
|
||||
IrInstructionIdBitCast,
|
||||
IrInstructionIdBitCastGen,
|
||||
IrInstructionIdWidenOrShorten,
|
||||
IrInstructionIdIntToPtr,
|
||||
|
@ -2645,7 +2644,6 @@ struct IrInstructionContainerInitList {
|
|||
IrInstruction *elem_type;
|
||||
size_t item_count;
|
||||
IrInstruction **items;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionContainerInitFieldsField {
|
||||
|
@ -3136,18 +3134,10 @@ struct IrInstructionPtrCastGen {
|
|||
bool safety_check_on;
|
||||
};
|
||||
|
||||
struct IrInstructionBitCast {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *dest_type;
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionBitCastGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *operand;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionWidenOrShorten {
|
||||
|
@ -3590,6 +3580,7 @@ enum ResultLocId {
|
|||
ResultLocIdPeer,
|
||||
ResultLocIdPeerParent,
|
||||
ResultLocIdInstruction,
|
||||
ResultLocIdBitCast,
|
||||
};
|
||||
|
||||
struct ResultLoc {
|
||||
|
@ -3644,6 +3635,13 @@ struct ResultLocInstruction {
|
|||
ResultLoc base;
|
||||
};
|
||||
|
||||
// The source_instruction is the destination type
|
||||
struct ResultLocBitCast {
|
||||
ResultLoc base;
|
||||
|
||||
ResultLoc *parent;
|
||||
};
|
||||
|
||||
static const size_t slice_ptr_index = 0;
|
||||
static const size_t slice_len_index = 1;
|
||||
|
||||
|
|
|
@ -3145,12 +3145,7 @@ static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable,
|
|||
uint32_t alignment = get_abi_alignment(g, actual_type);
|
||||
return gen_load_untyped(g, bitcasted_ptr, alignment, false, "");
|
||||
} else {
|
||||
assert(instruction->tmp_ptr != nullptr);
|
||||
LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(get_llvm_type(g, actual_type), 0);
|
||||
LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, wanted_ptr_type_ref, "");
|
||||
uint32_t alignment = get_abi_alignment(g, wanted_type);
|
||||
gen_store_untyped(g, value, bitcasted_ptr, alignment, false);
|
||||
return instruction->tmp_ptr;
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5520,7 +5515,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
|||
case IrInstructionIdPtrCastSrc:
|
||||
case IrInstructionIdCmpxchgSrc:
|
||||
case IrInstructionIdLoadPtr:
|
||||
case IrInstructionIdBitCast:
|
||||
case IrInstructionIdGlobalAsm:
|
||||
case IrInstructionIdHasDecl:
|
||||
case IrInstructionIdUndeclaredIdent:
|
||||
|
@ -6837,9 +6831,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 == IrInstructionIdContainerInitList) {
|
||||
IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction;
|
||||
slot = &container_init_list_instruction->tmp_ptr;
|
||||
} else if (instruction->id == IrInstructionIdSlice) {
|
||||
IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
|
||||
slot = &slice_instruction->tmp_ptr;
|
||||
|
@ -6861,9 +6852,6 @@ static void do_code_gen(CodeGen *g) {
|
|||
} else if (instruction->id == IrInstructionIdLoadPtrGen) {
|
||||
IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction;
|
||||
slot = &load_ptr_inst->tmp_ptr;
|
||||
} else if (instruction->id == IrInstructionIdBitCastGen) {
|
||||
IrInstructionBitCastGen *bit_cast_inst = (IrInstructionBitCastGen *)instruction;
|
||||
slot = &bit_cast_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);
|
||||
|
|
178
src/ir.cpp
178
src/ir.cpp
|
@ -780,10 +780,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) {
|
|||
return IrInstructionIdPtrCastGen;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) {
|
||||
return IrInstructionIdBitCast;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) {
|
||||
return IrInstructionIdBitCastGen;
|
||||
}
|
||||
|
@ -2429,20 +2425,6 @@ static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *sourc
|
|||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *dest_type, IrInstruction *value)
|
||||
{
|
||||
IrInstructionBitCast *instruction = ir_build_instruction<IrInstructionBitCast>(
|
||||
irb, scope, source_node);
|
||||
instruction->dest_type = dest_type;
|
||||
instruction->value = value;
|
||||
|
||||
ir_ref_instruction(dest_type, irb->current_basic_block);
|
||||
ir_ref_instruction(value, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_bit_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction,
|
||||
IrInstruction *operand, ZigType *ty)
|
||||
{
|
||||
|
@ -4836,18 +4818,23 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
|||
}
|
||||
case BuiltinFnIdBitCast:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
AstNode *dest_type_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *dest_type = ir_gen_node(irb, dest_type_node, scope);
|
||||
if (dest_type == irb->codegen->invalid_instruction)
|
||||
return dest_type;
|
||||
|
||||
ResultLocBitCast *result_loc_bit_cast = allocate<ResultLocBitCast>(1);
|
||||
result_loc_bit_cast->base.id = ResultLocIdBitCast;
|
||||
result_loc_bit_cast->base.source_instruction = dest_type;
|
||||
result_loc_bit_cast->parent = result_loc;
|
||||
|
||||
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
|
||||
IrInstruction *arg1_value = ir_gen_node_extra(irb, arg1_node, scope, LValNone,
|
||||
&result_loc_bit_cast->base);
|
||||
if (arg1_value == irb->codegen->invalid_instruction)
|
||||
return arg1_value;
|
||||
|
||||
IrInstruction *bit_cast = ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value);
|
||||
return ir_lval_wrap(irb, scope, bit_cast, lval, result_loc);
|
||||
return ir_lval_wrap(irb, scope, arg1_value, lval, result_loc);
|
||||
}
|
||||
case BuiltinFnIdIntToPtr:
|
||||
{
|
||||
|
@ -14059,9 +14046,10 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
|
|||
bool var_class_requires_const = false;
|
||||
|
||||
IrInstruction *var_ptr = decl_var_instruction->ptr->child;
|
||||
// if this assertion trips there may be a missing ir_expr_wrap in pass1 IR generation.
|
||||
ir_assert(var_ptr != nullptr, &decl_var_instruction->base);
|
||||
if (type_is_invalid(var_ptr->value.type)) {
|
||||
// if this is null, a compiler error happened and did not initialize the variable.
|
||||
// if there are no compile errors there may be a missing ir_expr_wrap in pass1 IR generation.
|
||||
if (var_ptr == nullptr || type_is_invalid(var_ptr->value.type)) {
|
||||
ir_assert(var_ptr != nullptr || ira->codegen->errors.length != 0, &decl_var_instruction->base);
|
||||
var->var_type = ira->codegen->builtin_types.entry_invalid;
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
@ -14528,6 +14516,7 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, IrInstruction *suspe
|
|||
zig_unreachable();
|
||||
case ResultLocIdNone:
|
||||
case ResultLocIdVar:
|
||||
case ResultLocIdBitCast:
|
||||
return nullptr;
|
||||
case ResultLocIdInstruction:
|
||||
return result_loc->source_instruction->child->value.type;
|
||||
|
@ -14539,6 +14528,28 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, IrInstruction *suspe
|
|||
zig_unreachable();
|
||||
}
|
||||
|
||||
static bool type_can_bit_cast(ZigType *t) {
|
||||
switch (t->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdEnumLiteral:
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdPointer:
|
||||
return false;
|
||||
default:
|
||||
// TODO list these types out explicitly, there are probably some other invalid ones here
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// give nullptr for value to resolve it at runtime
|
||||
// returns a result location, or nullptr if the result location was already taken care of
|
||||
// when calling this function, at the callsite must check for result type noreturn and propagate it up
|
||||
|
@ -14676,6 +14687,50 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s
|
|||
result_loc->resolved_loc = parent_result_loc;
|
||||
return result_loc->resolved_loc;
|
||||
}
|
||||
case ResultLocIdBitCast: {
|
||||
ResultLocBitCast *result_bit_cast = reinterpret_cast<ResultLocBitCast *>(result_loc);
|
||||
ZigType *dest_type = ir_resolve_type(ira, result_bit_cast->base.source_instruction->child);
|
||||
if (type_is_invalid(dest_type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (get_codegen_ptr_type(dest_type) != nullptr) {
|
||||
ir_add_error(ira, result_loc->source_instruction,
|
||||
buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
if (!type_can_bit_cast(dest_type)) {
|
||||
ir_add_error(ira, result_loc->source_instruction,
|
||||
buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
if (get_codegen_ptr_type(value_type) != nullptr) {
|
||||
ir_add_error(ira, suspend_source_instr,
|
||||
buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&value_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
if (!type_can_bit_cast(value_type)) {
|
||||
ir_add_error(ira, suspend_source_instr,
|
||||
buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&value_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
|
||||
IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent,
|
||||
dest_type, nullptr);
|
||||
if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
|
||||
parent_result_loc->value.type->id == ZigTypeIdUnreachable)
|
||||
{
|
||||
return parent_result_loc;
|
||||
}
|
||||
ZigType *ptr_type = get_pointer_to_type(ira->codegen, value_type, false);
|
||||
result_loc->written = true;
|
||||
result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr, parent_result_loc,
|
||||
ptr_type, result_bit_cast->base.source_instruction, false);
|
||||
return result_loc->resolved_loc;
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
@ -22755,28 +22810,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
|
|||
zig_unreachable();
|
||||
}
|
||||
|
||||
static bool type_can_bit_cast(ZigType *t) {
|
||||
switch (t->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdEnumLiteral:
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdPointer:
|
||||
return false;
|
||||
default:
|
||||
// TODO list these types out explicitly, there are probably some other invalid ones here
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
|
||||
ZigType *dest_type)
|
||||
{
|
||||
|
@ -22829,50 +22862,10 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_
|
|||
}
|
||||
|
||||
IrInstruction *result = ir_build_bit_cast_gen(ira, source_instr, value, dest_type);
|
||||
if (handle_is_ptr(dest_type) && !handle_is_ptr(src_type)) {
|
||||
ir_add_alloca(ira, result, dest_type);
|
||||
}
|
||||
assert(!(handle_is_ptr(dest_type) && !handle_is_ptr(src_type)));
|
||||
return result;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) {
|
||||
IrInstruction *dest_type_value = instruction->dest_type->child;
|
||||
ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
|
||||
if (type_is_invalid(dest_type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
IrInstruction *value = instruction->value->child;
|
||||
ZigType *src_type = value->value.type;
|
||||
if (type_is_invalid(src_type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (get_codegen_ptr_type(src_type) != nullptr) {
|
||||
ir_add_error(ira, value,
|
||||
buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
if (!type_can_bit_cast(src_type)) {
|
||||
ir_add_error(ira, dest_type_value,
|
||||
buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
if (get_codegen_ptr_type(dest_type) != nullptr) {
|
||||
ir_add_error(ira, dest_type_value,
|
||||
buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
if (!type_can_bit_cast(dest_type)) {
|
||||
ir_add_error(ira, dest_type_value,
|
||||
buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
return ir_analyze_bit_cast(ira, &instruction->base, value, dest_type);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target,
|
||||
ZigType *ptr_type)
|
||||
{
|
||||
|
@ -24089,8 +24082,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
|
|||
return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction);
|
||||
case IrInstructionIdPtrCastSrc:
|
||||
return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction);
|
||||
case IrInstructionIdBitCast:
|
||||
return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction);
|
||||
case IrInstructionIdIntToPtr:
|
||||
return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction);
|
||||
case IrInstructionIdPtrToInt:
|
||||
|
@ -24386,7 +24377,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
|||
case IrInstructionIdTestComptime:
|
||||
case IrInstructionIdPtrCastSrc:
|
||||
case IrInstructionIdPtrCastGen:
|
||||
case IrInstructionIdBitCast:
|
||||
case IrInstructionIdBitCastGen:
|
||||
case IrInstructionIdWidenOrShorten:
|
||||
case IrInstructionIdPtrToInt:
|
||||
|
|
|
@ -219,6 +219,12 @@ static void ir_print_result_loc_peer(IrPrint *irp, ResultLocPeer *result_loc_pee
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_result_loc_bit_cast(IrPrint *irp, ResultLocBitCast *result_loc_bit_cast) {
|
||||
fprintf(irp->f, "bitcast(ty=");
|
||||
ir_print_other_instruction(irp, result_loc_bit_cast->base.source_instruction);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {
|
||||
switch (result_loc->id) {
|
||||
case ResultLocIdInvalid:
|
||||
|
@ -235,6 +241,8 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {
|
|||
return ir_print_result_loc_instruction(irp, (ResultLocInstruction *)result_loc);
|
||||
case ResultLocIdPeer:
|
||||
return ir_print_result_loc_peer(irp, (ResultLocPeer *)result_loc);
|
||||
case ResultLocIdBitCast:
|
||||
return ir_print_result_loc_bit_cast(irp, (ResultLocBitCast *)result_loc);
|
||||
case ResultLocIdPeerParent:
|
||||
fprintf(irp->f, "peer_parent");
|
||||
return;
|
||||
|
@ -1011,14 +1019,6 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc
|
|||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
|
||||
fprintf(irp->f, "@bitCast(");
|
||||
ir_print_other_instruction(irp, instruction->dest_type);
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_bit_cast_gen(IrPrint *irp, IrInstructionBitCastGen *instruction) {
|
||||
fprintf(irp->f, "@bitCast(");
|
||||
ir_print_other_instruction(irp, instruction->operand);
|
||||
|
@ -1818,9 +1818,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
case IrInstructionIdPtrCastGen:
|
||||
ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBitCast:
|
||||
ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBitCastGen:
|
||||
ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue
Block a user