authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-21 17:24:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-21 23:21:07-07:00
log0e2b9ac7770df07212d4d1cbfb15c3aaed0bef18
tree84aa414d185d628269743a644188dcdfd8e8497e
parentbe71195bba13256f0e0a955833b2ada3a27492fc

stage2: fix unsigned integer to signed integer coercion


4 files changed, 20 insertions(+), 12 deletions(-)

src/Sema.zig+1-1
...@@ -9565,7 +9565,7 @@ fn coerce(...@@ -9565,7 +9565,7 @@ fn coerce(
9565 const src_info = inst_ty.intInfo(target);9565 const src_info = inst_ty.intInfo(target);
9566 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or9566 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or
9567 // small enough unsigned ints can get casted to large enough signed ints9567 // small enough unsigned ints can get casted to large enough signed ints
9568 (src_info.signedness == .signed and dst_info.signedness == .unsigned and dst_info.bits > src_info.bits))9568 (dst_info.signedness == .signed and dst_info.bits > src_info.bits))
9569 {9569 {
9570 try sema.requireRuntimeBlock(block, inst_src);9570 try sema.requireRuntimeBlock(block, inst_src);
9571 return block.addTyOp(.intcast, dest_type, inst);9571 return block.addTyOp(.intcast, dest_type, inst);
src/codegen/llvm.zig+13-5
...@@ -2032,14 +2032,22 @@ pub const FuncGen = struct {...@@ -2032,14 +2032,22 @@ pub const FuncGen = struct {
2032 if (self.liveness.isUnused(inst))2032 if (self.liveness.isUnused(inst))
2033 return null;2033 return null;
20342034
2035 const target = self.dg.module.getTarget();
2035 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2036 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2037 const dest_ty = self.air.typeOfIndex(inst);
2038 const dest_info = dest_ty.intInfo(target);
2039 const dest_llvm_ty = try self.dg.llvmType(dest_ty);
2036 const operand = try self.resolveInst(ty_op.operand);2040 const operand = try self.resolveInst(ty_op.operand);
2037 const inst_ty = self.air.typeOfIndex(inst);2041 const operand_ty = self.air.typeOf(ty_op.operand);
2042 const operand_info = operand_ty.intInfo(target);
20382043
2039 const signed = inst_ty.isSignedInt();2044 if (operand_info.bits < dest_info.bits) {
2040 // TODO: Should we use intcast here or just a simple bitcast?2045 switch (operand_info.signedness) {
2041 // LLVM does truncation vs bitcast (+signed extension) in the intcast depending on the sizes2046 .signed => return self.builder.buildSExt(operand, dest_llvm_ty, ""),
2042 return self.builder.buildIntCast2(operand, try self.dg.llvmType(inst_ty), llvm.Bool.fromBool(signed), "");2047 .unsigned => return self.builder.buildZExt(operand, dest_llvm_ty, ""),
2048 }
2049 }
2050 return self.builder.buildTrunc(operand, dest_llvm_ty, "");
2043 }2051 }
20442052
2045 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2053 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
test/behavior/widening.zig+6
...@@ -11,3 +11,9 @@ test "integer widening" {...@@ -11,3 +11,9 @@ test "integer widening" {
11 var f: u128 = e;11 var f: u128 = e;
12 try expect(f == a);12 try expect(f == a);
13}13}
14
15test "implicit unsigned integer to signed integer" {
16 var a: u8 = 250;
17 var b: i16 = a;
18 try expect(b == 250);
19}
test/behavior/widening_stage1.zig-6
...@@ -2,12 +2,6 @@ const std = @import("std");...@@ -2,12 +2,6 @@ const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const mem = std.mem;3const mem = std.mem;
44
5test "implicit unsigned integer to signed integer" {
6 var a: u8 = 250;
7 var b: i16 = a;
8 try expect(b == 250);
9}
10
11test "float widening" {5test "float widening" {
12 var a: f16 = 12.34;6 var a: f16 = 12.34;
13 var b: f32 = a;7 var b: f32 = a;