| author | |
| committer | |
| log | 0e2b9ac7770df07212d4d1cbfb15c3aaed0bef18 |
| tree | 84aa414d185d628269743a644188dcdfd8e8497e |
| parent | be71195bba13256f0e0a955833b2ada3a27492fc |
4 files changed, 20 insertions(+), 12 deletions(-)
src/Sema.zig+1-1| ... | ... | @@ -9565,7 +9565,7 @@ fn coerce( |
| 9565 | 9565 | const src_info = inst_ty.intInfo(target); |
| 9566 | 9566 | if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or |
| 9567 | 9567 | // 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 | 9570 | try sema.requireRuntimeBlock(block, inst_src); |
| 9571 | 9571 | return block.addTyOp(.intcast, dest_type, inst); |
src/codegen/llvm.zig+13-5| ... | ... | @@ -2032,14 +2032,22 @@ pub const FuncGen = struct { |
| 2032 | 2032 | if (self.liveness.isUnused(inst)) |
| 2033 | 2033 | return null; |
| 2034 | 2034 | |
| 2035 | const target = self.dg.module.getTarget(); | |
| 2035 | 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 | 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); | |
| 2038 | 2043 | |
| 2039 | const signed = inst_ty.isSignedInt(); | |
| 2040 | // TODO: Should we use intcast here or just a simple bitcast? | |
| 2041 | // LLVM does truncation vs bitcast (+signed extension) in the intcast depending on the sizes | |
| 2042 | return self.builder.buildIntCast2(operand, try self.dg.llvmType(inst_ty), llvm.Bool.fromBool(signed), ""); | |
| 2044 | if (operand_info.bits < dest_info.bits) { | |
| 2045 | switch (operand_info.signedness) { | |
| 2046 | .signed => return self.builder.buildSExt(operand, dest_llvm_ty, ""), | |
| 2047 | .unsigned => return self.builder.buildZExt(operand, dest_llvm_ty, ""), | |
| 2048 | } | |
| 2049 | } | |
| 2050 | return self.builder.buildTrunc(operand, dest_llvm_ty, ""); | |
| 2043 | 2051 | } |
| 2044 | 2052 | |
| 2045 | 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 | 11 | var f: u128 = e; |
| 12 | 12 | try expect(f == a); |
| 13 | 13 | } |
| 14 | ||
| 15 | test "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 | 2 | const expect = std.testing.expect; |
| 3 | 3 | const mem = std.mem; |
| 4 | 4 | |
| 5 | test "implicit unsigned integer to signed integer" { | |
| 6 | var a: u8 = 250; | |
| 7 | var b: i16 = a; | |
| 8 | try expect(b == 250); | |
| 9 | } | |
| 10 | ||
| 11 | 5 | test "float widening" { |
| 12 | 6 | var a: f16 = 12.34; |
| 13 | 7 | var b: f32 = a; |