mirror of
https://github.com/ziglang/zig.git
synced 2025-02-10 22:50:18 +00:00
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:
parent
cbce61a209
commit
0c5f897904
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
28
src/ir.cpp
28
src/ir.cpp
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user