authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-22 08:49:27-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-22 08:49:27-05:00
log0c5f8979045ff05e713bb1b7341496012189650f
treeb1a1fe8b16d544fb3fb5e6f25858204b21f52b34
parentcbce61a209897598cf093180ef6b5d71c9566d6a
signaturelock-open Commit is signed but in an unrecognized format.

fix `@bitCast` when src/dest types have mismatched handle_is_ptr

* 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 coreclr7823 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 sytsem7826 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};
30573058
3059struct IrInstructionBitCastGen {
3060 IrInstruction base;
3061
3062 IrInstruction *operand;
3063 LLVMValueRef tmp_ptr;
3064};
3065
3058struct IrInstructionWidenOrShorten {3066struct IrInstructionWidenOrShorten {
3059 IrInstruction base;3067 IrInstruction base;
30603068
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}
30743074
3075static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable,3075static 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 cast3080 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}
30853103
3086static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable,3104static 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();
54735492
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}
746746
747static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) {
748 return IrInstructionIdBitCastGen;
749}
750
747static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) {751static 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;
23192323
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);
23222326
2323 return &instruction->base;2327 return &instruction->base;
2324}2328}
23252329
2330static 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
2326static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, AstNode *source_node,2343static 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 }
2133721354
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}
2134321361
...@@ -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();
2235122370
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
920920
921static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {921static 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}
930928
929static 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
931static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {935static 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
98test "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}