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
opencl</code></pre>
<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.
Not all standard library code requires operating system abstractions, however,
so things such as generic data structures work an all above platforms.

View File

@ -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;

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,
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);

View File

@ -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<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,
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:

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) {
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;

View File

@ -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();
}