diff --git a/doc/langref.html.in b/doc/langref.html.in index 3a3eaf708c3c82f9843be7c06a249529de909cb0..9a286cb0638b9df9d9a970d75579d6e4523e38e7 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -7823,7 +7823,7 @@ Environments: coreclr opencl

- The Zig Standard Library ({#syntax#}@import("std"){#endsyntax#}) has architecture, environment, and operating sytsem + The Zig Standard Library ({#syntax#}@import("std"){#endsyntax#}) has architecture, environment, and operating system abstractions, and thus takes additional work to support more platforms. Not all standard library code requires operating system abstractions, however, so things such as generic data structures work an all above platforms. diff --git a/src/all_types.hpp b/src/all_types.hpp index fe36eb3a5d3ae5fa345c80a63ffc65371d9be7f1..29598672cd4b58458d11c77b88b88ac1cfcf251e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2198,6 +2198,7 @@ enum IrInstructionId { IrInstructionIdPtrCastSrc, IrInstructionIdPtrCastGen, IrInstructionIdBitCast, + IrInstructionIdBitCastGen, IrInstructionIdWidenOrShorten, IrInstructionIdIntToPtr, IrInstructionIdPtrToInt, @@ -3055,6 +3056,13 @@ struct IrInstructionBitCast { IrInstruction *value; }; +struct IrInstructionBitCastGen { + IrInstruction base; + + IrInstruction *operand; + LLVMValueRef tmp_ptr; +}; + struct IrInstructionWidenOrShorten { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index 6c9e8ccc4bae79bcaaf9f8d7b5e3394631d53ffb..c43611e8af8206d4fbc04dcd9279268899cfc2c9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3073,14 +3073,32 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, } static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable, - IrInstructionBitCast *instruction) + IrInstructionBitCastGen *instruction) { ZigType *wanted_type = instruction->base.value.type; - LLVMValueRef value = ir_llvm_value(g, instruction->value); - // We either bitcast the value directly or bitcast the pointer which does a pointer cast - LLVMTypeRef wanted_type_ref = handle_is_ptr(wanted_type) ? - LLVMPointerType(wanted_type->type_ref, 0) : wanted_type->type_ref; - return LLVMBuildBitCast(g->builder, value, wanted_type_ref, ""); + ZigType *actual_type = instruction->operand->value.type; + LLVMValueRef value = ir_llvm_value(g, instruction->operand); + + bool wanted_is_ptr = handle_is_ptr(wanted_type); + bool actual_is_ptr = handle_is_ptr(actual_type); + if (wanted_is_ptr == actual_is_ptr) { + // We either bitcast the value directly or bitcast the pointer which does a pointer cast + LLVMTypeRef wanted_type_ref = wanted_is_ptr ? + LLVMPointerType(wanted_type->type_ref, 0) : wanted_type->type_ref; + return LLVMBuildBitCast(g->builder, value, wanted_type_ref, ""); + } else if (actual_is_ptr) { + LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(wanted_type->type_ref, 0); + LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, value, wanted_ptr_type_ref, ""); + 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(actual_type->type_ref, 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; + } } static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable, @@ -5469,6 +5487,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdPtrCastSrc: case IrInstructionIdCmpxchgSrc: case IrInstructionIdLoadPtr: + case IrInstructionIdBitCast: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5565,8 +5584,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); case IrInstructionIdPtrCastGen: return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); - case IrInstructionIdBitCast: - return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction); + case IrInstructionIdBitCastGen: + return ir_render_bit_cast(g, executable, (IrInstructionBitCastGen *)instruction); case IrInstructionIdWidenOrShorten: return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction); case IrInstructionIdPtrToInt: @@ -6764,6 +6783,9 @@ 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); diff --git a/src/ir.cpp b/src/ir.cpp index 5fae81f0ce6c1bc31188adff9374b8a3f7877241..36f11cb10899888de3d2a652778bf36548c9ca8a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -744,6 +744,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { return IrInstructionIdBitCast; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) { + return IrInstructionIdBitCastGen; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) { return IrInstructionIdWidenOrShorten; } @@ -2317,12 +2321,25 @@ static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *s instruction->dest_type = dest_type; instruction->value = value; - if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block); + 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) +{ + IrInstructionBitCastGen *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = ty; + instruction->operand = operand; + + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) { @@ -21335,9 +21352,10 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_ return result; } - IrInstruction *result = ir_build_bit_cast(&ira->new_irb, source_instr->scope, - source_instr->source_node, nullptr, value); - result->value.type = dest_type; + 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); + } return result; } @@ -22347,6 +22365,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdAssertZero: case IrInstructionIdResizeSlice: case IrInstructionIdLoadPtrGen: + case IrInstructionIdBitCastGen: zig_unreachable(); case IrInstructionIdReturn: @@ -22804,6 +22823,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPtrCastSrc: case IrInstructionIdPtrCastGen: case IrInstructionIdBitCast: + case IrInstructionIdBitCastGen: case IrInstructionIdWidenOrShorten: case IrInstructionIdPtrToInt: case IrInstructionIdIntToPtr: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index c9058d4bc7df32cb6913b0806ea20d448dc24e74..4572b30deda022d34b30c8984d109ad635344730 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -920,14 +920,18 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { fprintf(irp->f, "@bitCast("); - if (instruction->dest_type) { - ir_print_other_instruction(irp, instruction->dest_type); - } + 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); + fprintf(irp->f, ")"); +} + static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) { fprintf(irp->f, "WidenOrShorten("); ir_print_other_instruction(irp, instruction->target); @@ -1692,6 +1696,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdBitCast: ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); break; + case IrInstructionIdBitCastGen: + ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction); + break; case IrInstructionIdWidenOrShorten: ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction); break; diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig index d409975548881374370e270145921966c0f193d8..e86c50885e36106ae720a727dc911807019b61a6 100644 --- a/test/stage1/behavior/bitcast.zig +++ b/test/stage1/behavior/bitcast.zig @@ -94,3 +94,21 @@ test "@bitCast extern structs at runtime and comptime" { S.doTheTest(); comptime S.doTheTest(); } + +test "bitcast packed struct to integer and back" { + const LevelUpMove = packed struct { + move_id: u9, + level: u7, + }; + const S = struct { + fn doTheTest() void { + var move = LevelUpMove{ .move_id = 1, .level = 2 }; + var v = @bitCast(u16, move); + var back_to_a_move = @bitCast(LevelUpMove, v); + expect(back_to_a_move.move_id == 1); + expect(back_to_a_move.level == 2); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +}