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:
78237823 coreclr
78247824 opencl</code></pre>
78257825 <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
78277827 abstractions, and thus takes additional work to support more platforms.
78287828 Not all standard library code requires operating system abstractions, however,
78297829 so things such as generic data structures work an all above platforms.
src/all_types.hpp+8
......@@ -2198,6 +2198,7 @@ enum IrInstructionId {
21982198 IrInstructionIdPtrCastSrc,
21992199 IrInstructionIdPtrCastGen,
22002200 IrInstructionIdBitCast,
2201 IrInstructionIdBitCastGen,
22012202 IrInstructionIdWidenOrShorten,
22022203 IrInstructionIdIntToPtr,
22032204 IrInstructionIdPtrToInt,
......@@ -3055,6 +3056,13 @@ struct IrInstructionBitCast {
30553056 IrInstruction *value;
30563057};
30573058
3059struct IrInstructionBitCastGen {
3060 IrInstruction base;
3061
3062 IrInstruction *operand;
3063 LLVMValueRef tmp_ptr;
3064};
3065
30583066struct IrInstructionWidenOrShorten {
30593067 IrInstruction base;
30603068
src/codegen.cpp+30-8
......@@ -3073,14 +3073,32 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
30733073}
30743074
30753075static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable,
3076 IrInstructionBitCast *instruction)
3076 IrInstructionBitCastGen *instruction)
30773077{
30783078 ZigType *wanted_type = instruction->base.value.type;
3079 LLVMValueRef value = ir_llvm_value(g, instruction->value);
3080 // We either bitcast the value directly or bitcast the pointer which does a pointer cast
3081 LLVMTypeRef wanted_type_ref = handle_is_ptr(wanted_type) ?
3082 LLVMPointerType(wanted_type->type_ref, 0) : wanted_type->type_ref;
3083 return LLVMBuildBitCast(g->builder, value, wanted_type_ref, "");
3079 ZigType *actual_type = instruction->operand->value.type;
3080 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
3081
3082 bool wanted_is_ptr = handle_is_ptr(wanted_type);
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 }
30843102}
30853103
30863104static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable,
......@@ -5469,6 +5487,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
54695487 case IrInstructionIdPtrCastSrc:
54705488 case IrInstructionIdCmpxchgSrc:
54715489 case IrInstructionIdLoadPtr:
5490 case IrInstructionIdBitCast:
54725491 zig_unreachable();
54735492
54745493 case IrInstructionIdDeclVarGen:
......@@ -5565,8 +5584,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
55655584 return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction);
55665585 case IrInstructionIdPtrCastGen:
55675586 return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction);
5568 case IrInstructionIdBitCast:
5569 return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction);
5587 case IrInstructionIdBitCastGen:
5588 return ir_render_bit_cast(g, executable, (IrInstructionBitCastGen *)instruction);
55705589 case IrInstructionIdWidenOrShorten:
55715590 return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction);
55725591 case IrInstructionIdPtrToInt:
......@@ -6764,6 +6783,9 @@ static void do_code_gen(CodeGen *g) {
67646783 } else if (instruction->id == IrInstructionIdLoadPtrGen) {
67656784 IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction;
67666785 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;
67676789 } else if (instruction->id == IrInstructionIdVectorToArray) {
67686790 IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction;
67696791 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 *) {
744744 return IrInstructionIdBitCast;
745745}
746746
747static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) {
748 return IrInstructionIdBitCastGen;
749}
750
747751static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) {
748752 return IrInstructionIdWidenOrShorten;
749753}
......@@ -2317,12 +2321,25 @@ static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *s
23172321 instruction->dest_type = dest_type;
23182322 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);
23212325 ir_ref_instruction(value, irb->current_basic_block);
23222326
23232327 return &instruction->base;
23242328}
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
23262343static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, AstNode *source_node,
23272344 IrInstruction *target)
23282345{
......@@ -21335,9 +21352,10 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_
2133521352 return result;
2133621353 }
2133721354
21338 IrInstruction *result = ir_build_bit_cast(&ira->new_irb, source_instr->scope,
21339 source_instr->source_node, nullptr, value);
21340 result->value.type = dest_type;
21355 IrInstruction *result = ir_build_bit_cast_gen(ira, source_instr, value, dest_type);
21356 if (handle_is_ptr(dest_type) && !handle_is_ptr(src_type)) {
21357 ir_add_alloca(ira, result, dest_type);
21358 }
2134121359 return result;
2134221360}
2134321361
......@@ -22347,6 +22365,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
2234722365 case IrInstructionIdAssertZero:
2234822366 case IrInstructionIdResizeSlice:
2234922367 case IrInstructionIdLoadPtrGen:
22368 case IrInstructionIdBitCastGen:
2235022369 zig_unreachable();
2235122370
2235222371 case IrInstructionIdReturn:
......@@ -22804,6 +22823,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2280422823 case IrInstructionIdPtrCastSrc:
2280522824 case IrInstructionIdPtrCastGen:
2280622825 case IrInstructionIdBitCast:
22826 case IrInstructionIdBitCastGen:
2280722827 case IrInstructionIdWidenOrShorten:
2280822828 case IrInstructionIdPtrToInt:
2280922829 case IrInstructionIdIntToPtr:
src/ir_print.cpp+10-3
......@@ -920,14 +920,18 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc
920920
921921static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
922922 fprintf(irp->f, "@bitCast(");
923 if (instruction->dest_type) {
924 ir_print_other_instruction(irp, instruction->dest_type);
925 }
923 ir_print_other_instruction(irp, instruction->dest_type);
926924 fprintf(irp->f, ",");
927925 ir_print_other_instruction(irp, instruction->value);
928926 fprintf(irp->f, ")");
929927}
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
931935static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
932936 fprintf(irp->f, "WidenOrShorten(");
933937 ir_print_other_instruction(irp, instruction->target);
......@@ -1692,6 +1696,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
16921696 case IrInstructionIdBitCast:
16931697 ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
16941698 break;
1699 case IrInstructionIdBitCastGen:
1700 ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction);
1701 break;
16951702 case IrInstructionIdWidenOrShorten:
16961703 ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction);
16971704 break;
test/stage1/behavior/bitcast.zig+18
......@@ -94,3 +94,21 @@ test "@bitCast extern structs at runtime and comptime" {
9494 S.doTheTest();
9595 comptime S.doTheTest();
9696}
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}