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)
This commit is contained in:
Andrew Kelley 2019-02-22 08:49:27 -05:00
parent cbce61a209
commit 0c5f897904
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
6 changed files with 91 additions and 16 deletions

View File

@ -7823,7 +7823,7 @@ Environments:
coreclr coreclr
opencl</code></pre> opencl</code></pre>
<p> <p>
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. abstractions, and thus takes additional work to support more platforms.
Not all standard library code requires operating system abstractions, however, Not all standard library code requires operating system abstractions, however,
so things such as generic data structures work an all above platforms. so things such as generic data structures work an all above platforms.

View File

@ -2198,6 +2198,7 @@ enum IrInstructionId {
IrInstructionIdPtrCastSrc, IrInstructionIdPtrCastSrc,
IrInstructionIdPtrCastGen, IrInstructionIdPtrCastGen,
IrInstructionIdBitCast, IrInstructionIdBitCast,
IrInstructionIdBitCastGen,
IrInstructionIdWidenOrShorten, IrInstructionIdWidenOrShorten,
IrInstructionIdIntToPtr, IrInstructionIdIntToPtr,
IrInstructionIdPtrToInt, IrInstructionIdPtrToInt,
@ -3055,6 +3056,13 @@ struct IrInstructionBitCast {
IrInstruction *value; IrInstruction *value;
}; };
struct IrInstructionBitCastGen {
IrInstruction base;
IrInstruction *operand;
LLVMValueRef tmp_ptr;
};
struct IrInstructionWidenOrShorten { struct IrInstructionWidenOrShorten {
IrInstruction base; IrInstruction base;

View File

@ -3073,14 +3073,32 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
} }
static LLVMValueRef ir_render_bit_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; ZigType *wanted_type = instruction->base.value.type;
LLVMValueRef value = ir_llvm_value(g, instruction->value); 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 // We either bitcast the value directly or bitcast the pointer which does a pointer cast
LLVMTypeRef wanted_type_ref = handle_is_ptr(wanted_type) ? LLVMTypeRef wanted_type_ref = wanted_is_ptr ?
LLVMPointerType(wanted_type->type_ref, 0) : wanted_type->type_ref; LLVMPointerType(wanted_type->type_ref, 0) : wanted_type->type_ref;
return LLVMBuildBitCast(g->builder, value, wanted_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, 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 IrInstructionIdPtrCastSrc:
case IrInstructionIdCmpxchgSrc: case IrInstructionIdCmpxchgSrc:
case IrInstructionIdLoadPtr: case IrInstructionIdLoadPtr:
case IrInstructionIdBitCast:
zig_unreachable(); zig_unreachable();
case IrInstructionIdDeclVarGen: case IrInstructionIdDeclVarGen:
@ -5565,8 +5584,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction);
case IrInstructionIdPtrCastGen: case IrInstructionIdPtrCastGen:
return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction);
case IrInstructionIdBitCast: case IrInstructionIdBitCastGen:
return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction); return ir_render_bit_cast(g, executable, (IrInstructionBitCastGen *)instruction);
case IrInstructionIdWidenOrShorten: case IrInstructionIdWidenOrShorten:
return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction); return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction);
case IrInstructionIdPtrToInt: case IrInstructionIdPtrToInt:
@ -6764,6 +6783,9 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdLoadPtrGen) { } else if (instruction->id == IrInstructionIdLoadPtrGen) {
IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction; IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction;
slot = &load_ptr_inst->tmp_ptr; 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) { } else if (instruction->id == IrInstructionIdVectorToArray) {
IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction;
alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type);

View File

@ -744,6 +744,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) {
return IrInstructionIdBitCast; return IrInstructionIdBitCast;
} }
static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) {
return IrInstructionIdBitCastGen;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) { static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) {
return IrInstructionIdWidenOrShorten; return IrInstructionIdWidenOrShorten;
} }
@ -2317,12 +2321,25 @@ static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *s
instruction->dest_type = dest_type; instruction->dest_type = dest_type;
instruction->value = value; 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); ir_ref_instruction(value, irb->current_basic_block);
return &instruction->base; return &instruction->base;
} }
static IrInstruction *ir_build_bit_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction,
IrInstruction *operand, ZigType *ty)
{
IrInstructionBitCastGen *instruction = ir_build_instruction<IrInstructionBitCastGen>(
&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, static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *target) IrInstruction *target)
{ {
@ -21335,9 +21352,10 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_
return result; return result;
} }
IrInstruction *result = ir_build_bit_cast(&ira->new_irb, source_instr->scope, IrInstruction *result = ir_build_bit_cast_gen(ira, source_instr, value, dest_type);
source_instr->source_node, nullptr, value); if (handle_is_ptr(dest_type) && !handle_is_ptr(src_type)) {
result->value.type = dest_type; ir_add_alloca(ira, result, dest_type);
}
return result; return result;
} }
@ -22347,6 +22365,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdAssertZero: case IrInstructionIdAssertZero:
case IrInstructionIdResizeSlice: case IrInstructionIdResizeSlice:
case IrInstructionIdLoadPtrGen: case IrInstructionIdLoadPtrGen:
case IrInstructionIdBitCastGen:
zig_unreachable(); zig_unreachable();
case IrInstructionIdReturn: case IrInstructionIdReturn:
@ -22804,6 +22823,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdPtrCastSrc: case IrInstructionIdPtrCastSrc:
case IrInstructionIdPtrCastGen: case IrInstructionIdPtrCastGen:
case IrInstructionIdBitCast: case IrInstructionIdBitCast:
case IrInstructionIdBitCastGen:
case IrInstructionIdWidenOrShorten: case IrInstructionIdWidenOrShorten:
case IrInstructionIdPtrToInt: case IrInstructionIdPtrToInt:
case IrInstructionIdIntToPtr: case IrInstructionIdIntToPtr:

View File

@ -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) { static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
fprintf(irp->f, "@bitCast("); 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, ","); fprintf(irp->f, ",");
ir_print_other_instruction(irp, instruction->value); ir_print_other_instruction(irp, instruction->value);
fprintf(irp->f, ")"); 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) { static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
fprintf(irp->f, "WidenOrShorten("); fprintf(irp->f, "WidenOrShorten(");
ir_print_other_instruction(irp, instruction->target); ir_print_other_instruction(irp, instruction->target);
@ -1692,6 +1696,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdBitCast: case IrInstructionIdBitCast:
ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
break; break;
case IrInstructionIdBitCastGen:
ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction);
break;
case IrInstructionIdWidenOrShorten: case IrInstructionIdWidenOrShorten:
ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction); ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction);
break; break;

View File

@ -94,3 +94,21 @@ test "@bitCast extern structs at runtime and comptime" {
S.doTheTest(); S.doTheTest();
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();
}