zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 11a60e87791c13d89d770c7925c744b5fe75e5c4 (tree)
parent f890de62948a0134a8d703dd2f1ee37701ec4c00
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Tue, 26 Oct 2021 16:42:44 -0700

stage2 LLVM backend: fix bitcast

Properly handle when the operand type, the result type, or both, are
by-ref values.

Diffstat:
Msrc/codegen/llvm.zig | 30+++++++++++++++++++++++++++---
Mtest/behavior/bitcast.zig | 6++++++
Mtest/behavior/bitcast_stage1.zig | 6------
3 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig @@ -3201,14 +3201,23 @@ pub const FuncGen = struct { const operand = try self.resolveInst(ty_op.operand); const operand_ty = self.air.typeOf(ty_op.operand); const inst_ty = self.air.typeOfIndex(inst); + const operand_is_ref = isByRef(operand_ty); + const result_is_ref = isByRef(inst_ty); const llvm_dest_ty = try self.dg.llvmType(inst_ty); + if (operand_is_ref and result_is_ref) { + // They are both pointers; just do a bitcast on the pointers :) + return self.builder.buildBitCast(operand, llvm_dest_ty.pointerType(0), ""); + } + if (operand_ty.zigTypeTag() == .Int and inst_ty.zigTypeTag() == .Pointer) { return self.builder.buildIntToPtr(operand, llvm_dest_ty, ""); - } else if (operand_ty.zigTypeTag() == .Vector and inst_ty.zigTypeTag() == .Array) { + } + + if (operand_ty.zigTypeTag() == .Vector and inst_ty.zigTypeTag() == .Array) { const target = self.dg.module.getTarget(); const elem_ty = operand_ty.childType(); - if (!isByRef(inst_ty)) { + if (!result_is_ref) { return self.dg.todo("implement bitcast vector to non-ref array", .{}); } const array_ptr = self.buildAlloca(llvm_dest_ty); @@ -3239,7 +3248,7 @@ pub const FuncGen = struct { const target = self.dg.module.getTarget(); const elem_ty = operand_ty.childType(); const llvm_vector_ty = try self.dg.llvmType(inst_ty); - if (!isByRef(operand_ty)) { + if (!operand_is_ref) { return self.dg.todo("implement bitcast non-ref array to vector", .{}); } @@ -3274,6 +3283,21 @@ pub const FuncGen = struct { } } + if (operand_is_ref) { + // Bitcast the operand pointer, then load. + const casted_ptr = self.builder.buildBitCast(operand, llvm_dest_ty.pointerType(0), ""); + return self.builder.buildLoad(casted_ptr, ""); + } + + if (result_is_ref) { + // Bitcast the result pointer, then store. + const result_ptr = self.buildAlloca(llvm_dest_ty); + const operand_llvm_ty = try self.dg.llvmType(operand_ty); + const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), ""); + _ = self.builder.buildStore(operand, casted_ptr); + return result_ptr; + } + return self.builder.buildBitCast(operand, llvm_dest_ty, ""); } diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig @@ -64,3 +64,9 @@ test "bitcast literal [4]u8 param to u32" { const ip = @bitCast(u32, [_]u8{ 255, 255, 255, 255 }); try expect(ip == maxInt(u32)); } + +test "bitcast generates a temporary value" { + var y = @as(u16, 0x55AA); + const x = @bitCast(u16, @bitCast([2]u8, y)); + try expect(y == x); +} diff --git a/test/behavior/bitcast_stage1.zig b/test/behavior/bitcast_stage1.zig @@ -129,9 +129,3 @@ test "triple level result location with bitcast sandwich passed as tuple element }; try S.foo(.{@as(f64, @bitCast(f32, @as(u32, 0x414570A4)))}); } - -test "bitcast generates a temporary value" { - var y = @as(u16, 0x55AA); - const x = @bitCast(u16, @bitCast([2]u8, y)); - try expectEqual(y, x); -}