From 0e38cc16d51178525e89774ce9151651b6a0e99a Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 2 Dec 2022 19:56:43 +0200 Subject: [PATCH] Sema: fix comparisons between lazy and runtime values Closes #12498 --- lib/std/fs.zig | 2 -- src/Sema.zig | 6 ++++-- src/arch/aarch64/CodeGen.zig | 2 +- src/arch/arm/CodeGen.zig | 2 +- src/arch/sparc64/CodeGen.zig | 2 +- src/arch/wasm/CodeGen.zig | 10 +++++----- src/arch/x86_64/CodeGen.zig | 2 +- src/codegen.zig | 14 +++++++------- src/codegen/llvm.zig | 2 +- src/codegen/spirv.zig | 4 ++-- src/link/Dwarf.zig | 2 +- src/value.zig | 21 +++++++++++++++------ test/behavior.zig | 1 + test/behavior/bugs/12498.zig | 8 ++++++++ 14 files changed, 48 insertions(+), 30 deletions(-) create mode 100644 test/behavior/bugs/12498.zig diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 3ef8e5319c..8ae21259ae 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -809,8 +809,6 @@ pub const IterableDir = struct { // and we avoid the code complexity here. const w = os.wasi; start_over: while (true) { - // TODO https://github.com/ziglang/zig/issues/12498 - _ = @sizeOf(w.dirent_t) + 1; // According to the WASI spec, the last entry might be truncated, // so we need to check if the left buffer contains the whole dirent. if (self.end_index - self.index < @sizeOf(w.dirent_t)) { diff --git a/src/Sema.zig b/src/Sema.zig index cc6e5e95d2..ad89408c26 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -20262,7 +20262,7 @@ fn analyzeShuffle( var buf: Value.ElemValueBuffer = undefined; const elem = mask.elemValueBuffer(sema.mod, i, &buf); if (elem.isUndef()) continue; - const int = elem.toSignedInt(); + const int = elem.toSignedInt(sema.mod.getTarget()); var unsigned: u32 = undefined; var chosen: u32 = undefined; if (int >= 0) { @@ -20304,7 +20304,7 @@ fn analyzeShuffle( values[i] = Value.undef; continue; } - const int = mask_elem_val.toSignedInt(); + const int = mask_elem_val.toSignedInt(sema.mod.getTarget()); const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int); if (int >= 0) { values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned); @@ -28299,6 +28299,7 @@ fn cmpNumeric( var lhs_bits: usize = undefined; if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { + try sema.resolveLazyValue(lhs_val); if (lhs_val.isUndef()) return sema.addConstUndef(Type.bool); if (lhs_val.isNan()) switch (op) { @@ -28357,6 +28358,7 @@ fn cmpNumeric( var rhs_bits: usize = undefined; if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { + try sema.resolveLazyValue(rhs_val); if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool); if (rhs_val.isNan()) switch (op) { diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 52f9a544b1..979472c5a5 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -6247,7 +6247,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { if (info.bits <= 64) { const unsigned = switch (info.signedness) { .signed => blk: { - const signed = typed_value.val.toSignedInt(); + const signed = typed_value.val.toSignedInt(target); break :blk @bitCast(u64, signed); }, .unsigned => typed_value.val.toUnsignedInt(target), diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 970b9376e5..4afadb2c58 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -6121,7 +6121,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { if (info.bits <= ptr_bits) { const unsigned = switch (info.signedness) { .signed => blk: { - const signed = @intCast(i32, typed_value.val.toSignedInt()); + const signed = @intCast(i32, typed_value.val.toSignedInt(target)); break :blk @bitCast(u32, signed); }, .unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)), diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index f22849c652..72c6b8021b 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -3786,7 +3786,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { if (info.bits <= 64) { const unsigned = switch (info.signedness) { .signed => blk: { - const signed = typed_value.val.toSignedInt(); + const signed = typed_value.val.toSignedInt(target); break :blk @bitCast(u64, signed); }, .unsigned => typed_value.val.toUnsignedInt(target), diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index ebfff25b2f..b11335f4c3 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2702,11 +2702,11 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { switch (int_info.signedness) { .signed => switch (int_info.bits) { 0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement( - val.toSignedInt(), + val.toSignedInt(target), @intCast(u6, int_info.bits), )) }, 33...64 => return WValue{ .imm64 = toTwosComplement( - val.toSignedInt(), + val.toSignedInt(target), @intCast(u7, int_info.bits), ) }, else => unreachable, @@ -2873,15 +2873,15 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { } }, .Int => switch (ty.intInfo(func.target).signedness) { - .signed => return @truncate(i32, val.toSignedInt()), + .signed => return @truncate(i32, val.toSignedInt(target)), .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(target))), }, .ErrorSet => { const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function return @bitCast(i32, kv.value); }, - .Bool => return @intCast(i32, val.toSignedInt()), - .Pointer => return @intCast(i32, val.toSignedInt()), + .Bool => return @intCast(i32, val.toSignedInt(target)), + .Pointer => return @intCast(i32, val.toSignedInt(target)), else => unreachable, // Programmer called this function for an illegal type } } diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 9efd50aec4..9b11eed1f2 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -7007,7 +7007,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { .Int => { const info = typed_value.ty.intInfo(self.target.*); if (info.bits <= ptr_bits and info.signedness == .signed) { - return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) }; + return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) }; } if (!(info.bits > ptr_bits or info.signedness == .signed)) { return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; diff --git a/src/codegen.zig b/src/codegen.zig index 5a28ce1860..0a20153396 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -459,7 +459,7 @@ pub fn generateSymbol( if (info.bits <= 8) { const x: u8 = switch (info.signedness) { .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)), - .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt())), + .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt(target))), }; try code.append(x); return Result{ .appended = {} }; @@ -488,13 +488,13 @@ pub fn generateSymbol( }, .signed => { if (info.bits <= 16) { - const x = @intCast(i16, typed_value.val.toSignedInt()); + const x = @intCast(i16, typed_value.val.toSignedInt(target)); mem.writeInt(i16, try code.addManyAsArray(2), x, endian); } else if (info.bits <= 32) { - const x = @intCast(i32, typed_value.val.toSignedInt()); + const x = @intCast(i32, typed_value.val.toSignedInt(target)); mem.writeInt(i32, try code.addManyAsArray(4), x, endian); } else { - const x = typed_value.val.toSignedInt(); + const x = typed_value.val.toSignedInt(target); mem.writeInt(i64, try code.addManyAsArray(8), x, endian); } }, @@ -536,13 +536,13 @@ pub fn generateSymbol( }, .signed => { if (info.bits <= 16) { - const x = @intCast(i16, int_val.toSignedInt()); + const x = @intCast(i16, int_val.toSignedInt(target)); mem.writeInt(i16, try code.addManyAsArray(2), x, endian); } else if (info.bits <= 32) { - const x = @intCast(i32, int_val.toSignedInt()); + const x = @intCast(i32, int_val.toSignedInt(target)); mem.writeInt(i32, try code.addManyAsArray(4), x, endian); } else { - const x = int_val.toSignedInt(); + const x = int_val.toSignedInt(target); mem.writeInt(i64, try code.addManyAsArray(8), x, endian); } }, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 6215a11e6f..3fd1effc21 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -8932,7 +8932,7 @@ pub const FuncGen = struct { if (elem.isUndef()) { val.* = llvm_i32.getUndef(); } else { - const int = elem.toSignedInt(); + const int = elem.toSignedInt(self.dg.module.getTarget()); const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); val.* = llvm_i32.constInt(unsigned, .False); } diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index ada3918baf..bd0c8bc53c 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -360,7 +360,7 @@ pub const DeclGen = struct { // Note, value is required to be sign-extended, so we don't need to mask off the upper bits. // See https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Literal - var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt()) else val.toUnsignedInt(target); + var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt(target)) else val.toUnsignedInt(target); const value: spec.LiteralContextDependentNumber = switch (backing_bits) { 1...32 => .{ .uint32 = @truncate(u32, int_bits) }, @@ -763,7 +763,7 @@ pub const DeclGen = struct { if (elem.isUndef()) { self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF); } else { - const int = elem.toSignedInt(); + const int = elem.toSignedInt(self.getTarget()); const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); self.func.body.writeOperand(spec.LiteralInteger, unsigned); } diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 843d14edd7..9e14695344 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -409,7 +409,7 @@ pub const DeclState = struct { // See https://github.com/ziglang/zig/issues/645 var int_buffer: Value.Payload.U64 = undefined; const field_int_val = value.enumToInt(ty, &int_buffer); - break :value @bitCast(u64, field_int_val.toSignedInt()); + break :value @bitCast(u64, field_int_val.toSignedInt(target)); } else @intCast(u64, field_i); mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); } diff --git a/src/value.zig b/src/value.zig index adff60983f..d3035946f9 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1201,8 +1201,8 @@ pub const Value = extern union { } /// Asserts the value is an integer and it fits in a i64 - pub fn toSignedInt(self: Value) i64 { - switch (self.tag()) { + pub fn toSignedInt(val: Value, target: Target) i64 { + switch (val.tag()) { .zero, .bool_false, .the_only_possible_value, // i0, u0 @@ -1212,10 +1212,19 @@ pub const Value = extern union { .bool_true, => return 1, - .int_u64 => return @intCast(i64, self.castTag(.int_u64).?.data), - .int_i64 => return self.castTag(.int_i64).?.data, - .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable, - .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable, + .int_u64 => return @intCast(i64, val.castTag(.int_u64).?.data), + .int_i64 => return val.castTag(.int_i64).?.data, + .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable, + .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable, + + .lazy_align => { + const ty = val.castTag(.lazy_align).?.data; + return @intCast(i64, ty.abiAlignment(target)); + }, + .lazy_size => { + const ty = val.castTag(.lazy_size).?.data; + return @intCast(i64, ty.abiSize(target)); + }, .undef => unreachable, else => unreachable, diff --git a/test/behavior.zig b/test/behavior.zig index 4e959fcf7d..3b6eb9c6ef 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -90,6 +90,7 @@ test { _ = @import("behavior/bugs/12430.zig"); _ = @import("behavior/bugs/12486.zig"); _ = @import("behavior/bugs/12488.zig"); + _ = @import("behavior/bugs/12498.zig"); _ = @import("behavior/bugs/12551.zig"); _ = @import("behavior/bugs/12644.zig"); _ = @import("behavior/bugs/12680.zig"); diff --git a/test/behavior/bugs/12498.zig b/test/behavior/bugs/12498.zig new file mode 100644 index 0000000000..3e4bafc2db --- /dev/null +++ b/test/behavior/bugs/12498.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const expect = std.testing.expect; + +const S = struct { a: usize }; +test "lazy abi size used in comparison" { + var rhs: i32 = 100; + try expect(@sizeOf(S) < rhs); +}