| author | |
| committer | |
| log | 0c5f8979045ff05e713bb1b7341496012189650f |
| tree | b1a1fe8b16d544fb3fb5e6f25858204b21f52b34 |
| parent | cbce61a209897598cf093180ef6b5d71c9566d6a |
| signature |
* separate BitCast and BitCastGen instructions
* closes #991
* closes #1934
* unrelated: fix typo in docs (thanks gamester for pointing it out)6 files changed, 91 insertions(+), 16 deletions(-)
doc/langref.html.in+1-1| ... | @@ -7823,7 +7823,7 @@ Environments: | ... | @@ -7823,7 +7823,7 @@ Environments: |
| 7823 | coreclr | 7823 | coreclr |
| 7824 | opencl</code></pre> | 7824 | opencl</code></pre> |
| 7825 | <p> | 7825 | <p> |
| 7826 | The Zig Standard Library ({#syntax#}@import("std"){#endsyntax#}) has architecture, environment, and operating sytsem | 7826 | The Zig Standard Library ({#syntax#}@import("std"){#endsyntax#}) has architecture, environment, and operating system |
| 7827 | abstractions, and thus takes additional work to support more platforms. | 7827 | abstractions, and thus takes additional work to support more platforms. |
| 7828 | Not all standard library code requires operating system abstractions, however, | 7828 | Not all standard library code requires operating system abstractions, however, |
| 7829 | so things such as generic data structures work an all above platforms. | 7829 | so things such as generic data structures work an all above platforms. |
src/all_types.hpp+8| ... | @@ -2198,6 +2198,7 @@ enum IrInstructionId { | ... | @@ -2198,6 +2198,7 @@ enum IrInstructionId { |
| 2198 | IrInstructionIdPtrCastSrc, | 2198 | IrInstructionIdPtrCastSrc, |
| 2199 | IrInstructionIdPtrCastGen, | 2199 | IrInstructionIdPtrCastGen, |
| 2200 | IrInstructionIdBitCast, | 2200 | IrInstructionIdBitCast, |
| 2201 | IrInstructionIdBitCastGen, | ||
| 2201 | IrInstructionIdWidenOrShorten, | 2202 | IrInstructionIdWidenOrShorten, |
| 2202 | IrInstructionIdIntToPtr, | 2203 | IrInstructionIdIntToPtr, |
| 2203 | IrInstructionIdPtrToInt, | 2204 | IrInstructionIdPtrToInt, |
| ... | @@ -3055,6 +3056,13 @@ struct IrInstructionBitCast { | ... | @@ -3055,6 +3056,13 @@ struct IrInstructionBitCast { |
| 3055 | IrInstruction *value; | 3056 | IrInstruction *value; |
| 3056 | }; | 3057 | }; |
| 3057 | 3058 | ||
| 3059 | struct IrInstructionBitCastGen { | ||
| 3060 | IrInstruction base; | ||
| 3061 | |||
| 3062 | IrInstruction *operand; | ||
| 3063 | LLVMValueRef tmp_ptr; | ||
| 3064 | }; | ||
| 3065 | |||
| 3058 | struct IrInstructionWidenOrShorten { | 3066 | struct IrInstructionWidenOrShorten { |
| 3059 | IrInstruction base; | 3067 | IrInstruction base; |
| 3060 | 3068 |
src/codegen.cpp+30-8| ... | @@ -3073,14 +3073,32 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, | ... | @@ -3073,14 +3073,32 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, |
| 3073 | } | 3073 | } |
| 3074 | 3074 | ||
| 3075 | static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable, | 3075 | static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable, |
| 3076 | IrInstructionBitCast *instruction) | 3076 | IrInstructionBitCastGen *instruction) |
| 3077 | { | 3077 | { |
| 3078 | ZigType *wanted_type = instruction->base.value.type; | 3078 | ZigType *wanted_type = instruction->base.value.type; |
| 3079 | LLVMValueRef value = ir_llvm_value(g, instruction->value); | 3079 | ZigType *actual_type = instruction->operand->value.type; |
| 3080 | // We either bitcast the value directly or bitcast the pointer which does a pointer cast | 3080 | LLVMValueRef value = ir_llvm_value(g, instruction->operand); |
| 3081 | LLVMTypeRef wanted_type_ref = handle_is_ptr(wanted_type) ? | 3081 | |
| 3082 | LLVMPointerType(wanted_type->type_ref, 0) : wanted_type->type_ref; | 3082 | bool wanted_is_ptr = handle_is_ptr(wanted_type); |
| 3083 | return LLVMBuildBitCast(g->builder, value, wanted_type_ref, ""); | 3083 | bool actual_is_ptr = handle_is_ptr(actual_type); |
| 3084 | if (wanted_is_ptr == actual_is_ptr) { | ||
| 3085 | // We either bitcast the value directly or bitcast the pointer which does a pointer cast | ||
| 3086 | LLVMTypeRef wanted_type_ref = wanted_is_ptr ? | ||
| 3087 | LLVMPointerType(wanted_type->type_ref, 0) : wanted_type->type_ref; | ||
| 3088 | return LLVMBuildBitCast(g->builder, value, wanted_type_ref, ""); | ||
| 3089 | } else if (actual_is_ptr) { | ||
| 3090 | LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(wanted_type->type_ref, 0); | ||
| 3091 | LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, value, wanted_ptr_type_ref, ""); | ||
| 3092 | uint32_t alignment = get_abi_alignment(g, actual_type); | ||
| 3093 | return gen_load_untyped(g, bitcasted_ptr, alignment, false, ""); | ||
| 3094 | } else { | ||
| 3095 | assert(instruction->tmp_ptr != nullptr); | ||
| 3096 | LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(actual_type->type_ref, 0); | ||
| 3097 | LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, wanted_ptr_type_ref, ""); | ||
| 3098 | uint32_t alignment = get_abi_alignment(g, wanted_type); | ||
| 3099 | gen_store_untyped(g, value, bitcasted_ptr, alignment, false); | ||
| 3100 | return instruction->tmp_ptr; | ||
| 3101 | } | ||
| 3084 | } | 3102 | } |
| 3085 | 3103 | ||
| 3086 | static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable, | 3104 | static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable, |
| ... | @@ -5469,6 +5487,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5469,6 +5487,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5469 | case IrInstructionIdPtrCastSrc: | 5487 | case IrInstructionIdPtrCastSrc: |
| 5470 | case IrInstructionIdCmpxchgSrc: | 5488 | case IrInstructionIdCmpxchgSrc: |
| 5471 | case IrInstructionIdLoadPtr: | 5489 | case IrInstructionIdLoadPtr: |
| 5490 | case IrInstructionIdBitCast: | ||
| 5472 | zig_unreachable(); | 5491 | zig_unreachable(); |
| 5473 | 5492 | ||
| 5474 | case IrInstructionIdDeclVarGen: | 5493 | case IrInstructionIdDeclVarGen: |
| ... | @@ -5565,8 +5584,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5565,8 +5584,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5565 | return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); | 5584 | return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); |
| 5566 | case IrInstructionIdPtrCastGen: | 5585 | case IrInstructionIdPtrCastGen: |
| 5567 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); | 5586 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); |
| 5568 | case IrInstructionIdBitCast: | 5587 | case IrInstructionIdBitCastGen: |
| 5569 | return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction); | 5588 | return ir_render_bit_cast(g, executable, (IrInstructionBitCastGen *)instruction); |
| 5570 | case IrInstructionIdWidenOrShorten: | 5589 | case IrInstructionIdWidenOrShorten: |
| 5571 | return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction); | 5590 | return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction); |
| 5572 | case IrInstructionIdPtrToInt: | 5591 | case IrInstructionIdPtrToInt: |
| ... | @@ -6764,6 +6783,9 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6764,6 +6783,9 @@ static void do_code_gen(CodeGen *g) { |
| 6764 | } else if (instruction->id == IrInstructionIdLoadPtrGen) { | 6783 | } else if (instruction->id == IrInstructionIdLoadPtrGen) { |
| 6765 | IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction; | 6784 | IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction; |
| 6766 | slot = &load_ptr_inst->tmp_ptr; | 6785 | slot = &load_ptr_inst->tmp_ptr; |
| 6786 | } else if (instruction->id == IrInstructionIdBitCastGen) { | ||
| 6787 | IrInstructionBitCastGen *bit_cast_inst = (IrInstructionBitCastGen *)instruction; | ||
| 6788 | slot = &bit_cast_inst->tmp_ptr; | ||
| 6767 | } else if (instruction->id == IrInstructionIdVectorToArray) { | 6789 | } else if (instruction->id == IrInstructionIdVectorToArray) { |
| 6768 | IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; | 6790 | IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; |
| 6769 | alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); | 6791 | alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); |
src/ir.cpp+24-4| ... | @@ -744,6 +744,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { | ... | @@ -744,6 +744,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { |
| 744 | return IrInstructionIdBitCast; | 744 | return IrInstructionIdBitCast; |
| 745 | } | 745 | } |
| 746 | 746 | ||
| 747 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) { | ||
| 748 | return IrInstructionIdBitCastGen; | ||
| 749 | } | ||
| 750 | |||
| 747 | static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) { | 751 | static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) { |
| 748 | return IrInstructionIdWidenOrShorten; | 752 | return IrInstructionIdWidenOrShorten; |
| 749 | } | 753 | } |
| ... | @@ -2317,12 +2321,25 @@ static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *s | ... | @@ -2317,12 +2321,25 @@ static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *s |
| 2317 | instruction->dest_type = dest_type; | 2321 | instruction->dest_type = dest_type; |
| 2318 | instruction->value = value; | 2322 | instruction->value = value; |
| 2319 | 2323 | ||
| 2320 | if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block); | 2324 | ir_ref_instruction(dest_type, irb->current_basic_block); |
| 2321 | ir_ref_instruction(value, irb->current_basic_block); | 2325 | ir_ref_instruction(value, irb->current_basic_block); |
| 2322 | 2326 | ||
| 2323 | return &instruction->base; | 2327 | return &instruction->base; |
| 2324 | } | 2328 | } |
| 2325 | 2329 | ||
| 2330 | static IrInstruction *ir_build_bit_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, | ||
| 2331 | IrInstruction *operand, ZigType *ty) | ||
| 2332 | { | ||
| 2333 | IrInstructionBitCastGen *instruction = ir_build_instruction<IrInstructionBitCastGen>( | ||
| 2334 | &ira->new_irb, source_instruction->scope, source_instruction->source_node); | ||
| 2335 | instruction->base.value.type = ty; | ||
| 2336 | instruction->operand = operand; | ||
| 2337 | |||
| 2338 | ir_ref_instruction(operand, ira->new_irb.current_basic_block); | ||
| 2339 | |||
| 2340 | return &instruction->base; | ||
| 2341 | } | ||
| 2342 | |||
| 2326 | static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, AstNode *source_node, | 2343 | static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2327 | IrInstruction *target) | 2344 | IrInstruction *target) |
| 2328 | { | 2345 | { |
| ... | @@ -21335,9 +21352,10 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -21335,9 +21352,10 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_ |
| 21335 | return result; | 21352 | return result; |
| 21336 | } | 21353 | } |
| 21337 | 21354 | ||
| 21338 | IrInstruction *result = ir_build_bit_cast(&ira->new_irb, source_instr->scope, | 21355 | IrInstruction *result = ir_build_bit_cast_gen(ira, source_instr, value, dest_type); |
| 21339 | source_instr->source_node, nullptr, value); | 21356 | if (handle_is_ptr(dest_type) && !handle_is_ptr(src_type)) { |
| 21340 | result->value.type = dest_type; | 21357 | ir_add_alloca(ira, result, dest_type); |
| 21358 | } | ||
| 21341 | return result; | 21359 | return result; |
| 21342 | } | 21360 | } |
| 21343 | 21361 | ||
| ... | @@ -22347,6 +22365,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio | ... | @@ -22347,6 +22365,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 22347 | case IrInstructionIdAssertZero: | 22365 | case IrInstructionIdAssertZero: |
| 22348 | case IrInstructionIdResizeSlice: | 22366 | case IrInstructionIdResizeSlice: |
| 22349 | case IrInstructionIdLoadPtrGen: | 22367 | case IrInstructionIdLoadPtrGen: |
| 22368 | case IrInstructionIdBitCastGen: | ||
| 22350 | zig_unreachable(); | 22369 | zig_unreachable(); |
| 22351 | 22370 | ||
| 22352 | case IrInstructionIdReturn: | 22371 | case IrInstructionIdReturn: |
| ... | @@ -22804,6 +22823,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -22804,6 +22823,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 22804 | case IrInstructionIdPtrCastSrc: | 22823 | case IrInstructionIdPtrCastSrc: |
| 22805 | case IrInstructionIdPtrCastGen: | 22824 | case IrInstructionIdPtrCastGen: |
| 22806 | case IrInstructionIdBitCast: | 22825 | case IrInstructionIdBitCast: |
| 22826 | case IrInstructionIdBitCastGen: | ||
| 22807 | case IrInstructionIdWidenOrShorten: | 22827 | case IrInstructionIdWidenOrShorten: |
| 22808 | case IrInstructionIdPtrToInt: | 22828 | case IrInstructionIdPtrToInt: |
| 22809 | case IrInstructionIdIntToPtr: | 22829 | case IrInstructionIdIntToPtr: |
src/ir_print.cpp+10-3| ... | @@ -920,14 +920,18 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc | ... | @@ -920,14 +920,18 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc |
| 920 | 920 | ||
| 921 | static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { | 921 | static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { |
| 922 | fprintf(irp->f, "@bitCast("); | 922 | fprintf(irp->f, "@bitCast("); |
| 923 | if (instruction->dest_type) { | 923 | ir_print_other_instruction(irp, instruction->dest_type); |
| 924 | ir_print_other_instruction(irp, instruction->dest_type); | ||
| 925 | } | ||
| 926 | fprintf(irp->f, ","); | 924 | fprintf(irp->f, ","); |
| 927 | ir_print_other_instruction(irp, instruction->value); | 925 | ir_print_other_instruction(irp, instruction->value); |
| 928 | fprintf(irp->f, ")"); | 926 | fprintf(irp->f, ")"); |
| 929 | } | 927 | } |
| 930 | 928 | ||
| 929 | static void ir_print_bit_cast_gen(IrPrint *irp, IrInstructionBitCastGen *instruction) { | ||
| 930 | fprintf(irp->f, "@bitCast("); | ||
| 931 | ir_print_other_instruction(irp, instruction->operand); | ||
| 932 | fprintf(irp->f, ")"); | ||
| 933 | } | ||
| 934 | |||
| 931 | static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) { | 935 | static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) { |
| 932 | fprintf(irp->f, "WidenOrShorten("); | 936 | fprintf(irp->f, "WidenOrShorten("); |
| 933 | ir_print_other_instruction(irp, instruction->target); | 937 | ir_print_other_instruction(irp, instruction->target); |
| ... | @@ -1692,6 +1696,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1692,6 +1696,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1692 | case IrInstructionIdBitCast: | 1696 | case IrInstructionIdBitCast: |
| 1693 | ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); | 1697 | ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); |
| 1694 | break; | 1698 | break; |
| 1699 | case IrInstructionIdBitCastGen: | ||
| 1700 | ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction); | ||
| 1701 | break; | ||
| 1695 | case IrInstructionIdWidenOrShorten: | 1702 | case IrInstructionIdWidenOrShorten: |
| 1696 | ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction); | 1703 | ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction); |
| 1697 | break; | 1704 | break; |
test/stage1/behavior/bitcast.zig+18| ... | @@ -94,3 +94,21 @@ test "@bitCast extern structs at runtime and comptime" { | ... | @@ -94,3 +94,21 @@ test "@bitCast extern structs at runtime and comptime" { |
| 94 | S.doTheTest(); | 94 | S.doTheTest(); |
| 95 | comptime S.doTheTest(); | 95 | comptime S.doTheTest(); |
| 96 | } | 96 | } |
| 97 | |||
| 98 | test "bitcast packed struct to integer and back" { | ||
| 99 | const LevelUpMove = packed struct { | ||
| 100 | move_id: u9, | ||
| 101 | level: u7, | ||
| 102 | }; | ||
| 103 | const S = struct { | ||
| 104 | fn doTheTest() void { | ||
| 105 | var move = LevelUpMove{ .move_id = 1, .level = 2 }; | ||
| 106 | var v = @bitCast(u16, move); | ||
| 107 | var back_to_a_move = @bitCast(LevelUpMove, v); | ||
| 108 | expect(back_to_a_move.move_id == 1); | ||
| 109 | expect(back_to_a_move.level == 2); | ||
| 110 | } | ||
| 111 | }; | ||
| 112 | S.doTheTest(); | ||
| 113 | comptime S.doTheTest(); | ||
| 114 | } |