authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-12 12:24:59-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-06-13 02:22:04-07:00
log083b7b483e1ad83d62ed7029822a82fff14953c5
tree3b534a1d71fa3bc1c511788d162db28b5250b470
parentb67995689df424a0cab9186fcaf7b09bb04ffc1a
signaturelock-open Commit is signed but in an unrecognized format.

riscv: zero registers when using register-wide operations

what was happening is that instructions like `lb` were only affecting the lower bytes of the register and leaving the top dirty. this would lead to situtations were `cmp_eq` for example was using `xor`, which was failing because of the left-over stuff in the top of the register. with this commit, we now zero out or truncate depending on the context, to ensure instructions like xor will provide proper results.

13 files changed, 72 insertions(+), 44 deletions(-)

src/arch/riscv64/CodeGen.zig+71-17
......@@ -1668,12 +1668,66 @@ fn allocReg(self: *Self, reg_class: abi.RegisterClass) !struct { Register, Regis
16681668 return .{ reg, lock };
16691669}
16701670
1671const PromoteOptions = struct {
1672 /// zeroes out the register before loading in the operand
1673 ///
1674 /// if the operand is already a register, it will truncate with 0
1675 zero: bool = false,
1676};
1677
16711678/// Similar to `allocReg` but will copy the MCValue into the Register unless `operand` is already
16721679/// a register, in which case it will return a possible lock to that register.
1673fn promoteReg(self: *Self, ty: Type, operand: MCValue) !struct { Register, ?RegisterLock } {
1674 if (operand == .register) return .{ operand.register, self.register_manager.lockReg(operand.register) };
1680fn promoteReg(self: *Self, ty: Type, operand: MCValue, options: PromoteOptions) !struct { Register, ?RegisterLock } {
1681 const zcu = self.bin_file.comp.module.?;
1682 const bit_size = ty.bitSize(zcu);
1683
1684 if (operand == .register) {
1685 const op_reg = operand.register;
1686 if (options.zero and op_reg.class() == .int) {
1687 // we make sure to emit the truncate manually because binOp will call this function
1688 // and it could cause an infinite loop
1689
1690 _ = try self.addInst(.{
1691 .tag = .slli,
1692 .ops = .rri,
1693 .data = .{
1694 .i_type = .{
1695 .imm12 = Immediate.u(64 - bit_size),
1696 .rd = op_reg,
1697 .rs1 = op_reg,
1698 },
1699 },
1700 });
1701
1702 _ = try self.addInst(.{
1703 .tag = .srli,
1704 .ops = .rri,
1705 .data = .{
1706 .i_type = .{
1707 .imm12 = Immediate.u(64 - bit_size),
1708 .rd = op_reg,
1709 .rs1 = op_reg,
1710 },
1711 },
1712 });
1713 }
1714
1715 return .{ op_reg, self.register_manager.lockReg(operand.register) };
1716 }
16751717
16761718 const reg, const lock = try self.allocReg(self.typeRegClass(ty));
1719
1720 if (options.zero and reg.class() == .int) {
1721 _ = try self.addInst(.{
1722 .tag = .pseudo,
1723 .ops = .pseudo_mv,
1724 .data = .{ .rr = .{
1725 .rd = reg,
1726 .rs = .zero,
1727 } },
1728 });
1729 }
1730
16771731 try self.genSetReg(ty, reg, operand);
16781732 return .{ reg, lock };
16791733}
......@@ -2124,10 +2178,10 @@ fn binOpRegister(
21242178 rhs: MCValue,
21252179 rhs_ty: Type,
21262180) !MCValue {
2127 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
2181 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs, .{ .zero = true });
21282182 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
21292183
2130 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
2184 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs, .{ .zero = true });
21312185 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
21322186
21332187 const dest_reg, const dest_lock = try self.allocReg(.int);
......@@ -2223,10 +2277,10 @@ fn binOpFloat(
22232277 const zcu = self.bin_file.comp.module.?;
22242278 const float_bits = lhs_ty.floatBits(zcu.getTarget());
22252279
2226 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
2280 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs, .{});
22272281 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
22282282
2229 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
2283 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs, .{});
22302284 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
22312285
22322286 const mir_tag: Mir.Inst.Tag = switch (tag) {
......@@ -2425,10 +2479,10 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
24252479 const result_mcv = try self.allocRegOrMem(inst, false);
24262480 const offset = result_mcv.load_frame;
24272481
2428 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
2482 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs, .{});
24292483 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
24302484
2431 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
2485 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs, .{});
24322486 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
24332487
24342488 const dest_reg, const dest_lock = try self.allocReg(.int);
......@@ -2559,7 +2613,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
25592613 1...8 => {
25602614 const max_val = std.math.pow(u16, 2, int_info.bits) - 1;
25612615
2562 const add_reg, const add_lock = try self.promoteReg(lhs_ty, lhs);
2616 const add_reg, const add_lock = try self.promoteReg(lhs_ty, lhs, .{});
25632617 defer if (add_lock) |lock| self.register_manager.unlockReg(lock);
25642618
25652619 const overflow_reg, const overflow_lock = try self.allocReg(.int);
......@@ -2645,10 +2699,10 @@ fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void {
26452699 const lhs_ty = self.typeOf(bin_op.lhs);
26462700 const rhs_ty = self.typeOf(bin_op.rhs);
26472701
2648 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
2702 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs, .{});
26492703 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
26502704
2651 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
2705 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs, .{});
26522706 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
26532707
26542708 const dest_reg, const dest_lock = try self.allocReg(.int);
......@@ -2678,10 +2732,10 @@ fn airBitOr(self: *Self, inst: Air.Inst.Index) !void {
26782732 const lhs_ty = self.typeOf(bin_op.lhs);
26792733 const rhs_ty = self.typeOf(bin_op.rhs);
26802734
2681 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
2735 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs, .{});
26822736 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
26832737
2684 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
2738 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs, .{});
26852739 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
26862740
26872741 const dest_reg, const dest_lock = try self.allocReg(.int);
......@@ -4706,10 +4760,10 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
47064760 const lhs_ty = Type.bool;
47074761 const rhs_ty = Type.bool;
47084762
4709 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs);
4763 const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs, .{});
47104764 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
47114765
4712 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs);
4766 const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs, .{});
47134767 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
47144768
47154769 const result_reg, const result_lock = try self.allocReg(.int);
......@@ -4905,7 +4959,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
49054959 const src_info: ?struct { addr_reg: Register, addr_lock: ?RegisterLock } = switch (src_mcv) {
49064960 .register_pair, .memory, .indirect, .load_frame => null,
49074961 .load_symbol => src: {
4908 const src_addr_reg, const src_addr_lock = try self.promoteReg(Type.usize, src_mcv.address());
4962 const src_addr_reg, const src_addr_lock = try self.promoteReg(Type.usize, src_mcv.address(), .{});
49094963 errdefer self.register_manager.unlockReg(src_addr_lock);
49104964
49114965 break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
......@@ -5463,7 +5517,7 @@ fn genSetMem(
54635517 .immediate => {
54645518 // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with
54655519 // a register allocation.
5466 const reg, const reg_lock = try self.promoteReg(ty, src_mcv);
5520 const reg, const reg_lock = try self.promoteReg(ty, src_mcv, .{});
54675521 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
54685522
54695523 return self.genSetMem(base, disp, ty, .{ .register = reg });
src/arch/riscv64/bits.zig+1-1
......@@ -102,7 +102,7 @@ pub const Memory = struct {
102102
103103pub const Immediate = union(enum) {
104104 signed: i32,
105 unsigned: u32,
105 unsigned: u64,
106106
107107 pub fn u(x: u64) Immediate {
108108 return .{ .unsigned = x };
test/behavior/array.zig-1
......@@ -542,7 +542,6 @@ test "sentinel element count towards the ABI size calculation" {
542542 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
543543 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
544544 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
545 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
546545
547546 const S = struct {
548547 fn doTheTest() !void {
test/behavior/bitcast.zig-3
......@@ -165,7 +165,6 @@ test "@bitCast packed structs at runtime and comptime" {
165165 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
166166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
167167 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
168 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
169168
170169 const Full = packed struct {
171170 number: u16,
......@@ -192,7 +191,6 @@ test "@bitCast packed structs at runtime and comptime" {
192191test "@bitCast extern structs at runtime and comptime" {
193192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
194193 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
196194
197195 const Full = extern struct {
198196 number: u16,
......@@ -227,7 +225,6 @@ test "bitcast packed struct to integer and back" {
227225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
228226 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
229227 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
230 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
231228
232229 const LevelUpMove = packed struct {
233230 move_id: u9,
test/behavior/cast.zig-2
......@@ -57,8 +57,6 @@ test "@intCast to comptime_int" {
5757}
5858
5959test "implicit cast comptime numbers to any type when the value fits" {
60 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
61
6260 const a: u64 = 255;
6361 var b: u8 = a;
6462 _ = &b;
test/behavior/error.zig-1
......@@ -740,7 +740,6 @@ test "ret_ptr doesn't cause own inferred error set to be resolved" {
740740
741741test "simple else prong allowed even when all errors handled" {
742742 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
743 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
744743
745744 const S = struct {
746745 fn foo() !u8 {
test/behavior/eval.zig-2
......@@ -395,7 +395,6 @@ test "return 0 from function that has u0 return type" {
395395test "statically initialized struct" {
396396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
397397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
398 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
399398
400399 st_init_str_foo.x += 1;
401400 try expect(st_init_str_foo.x == 14);
......@@ -787,7 +786,6 @@ test "array concatenation peer resolves element types - pointer" {
787786 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
788787 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
789788 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
790 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
791789
792790 var a = [2]u3{ 1, 7 };
793791 var b = [3]u8{ 200, 225, 255 };
test/behavior/math.zig-4
......@@ -605,8 +605,6 @@ fn testSignedNegationWrappingEval(x: i16) !void {
605605}
606606
607607test "unsigned negation wrapping" {
608 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
609
610608 try testUnsignedNegationWrappingEval(1);
611609 try comptime testUnsignedNegationWrappingEval(1);
612610}
......@@ -1436,8 +1434,6 @@ test "quad hex float literal parsing accurate" {
14361434}
14371435
14381436test "truncating shift left" {
1439 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1440
14411437 try testShlTrunc(maxInt(u16));
14421438 try comptime testShlTrunc(maxInt(u16));
14431439}
test/behavior/packed-struct.zig-2
......@@ -258,7 +258,6 @@ test "nested packed struct unaligned" {
258258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
259259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
260260 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
261 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
262261 if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet
263262
264263 const S1 = packed struct {
......@@ -331,7 +330,6 @@ test "byte-aligned field pointer offsets" {
331330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
332331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
333332 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
334 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
335333
336334 const S = struct {
337335 const A = packed struct {
test/behavior/reflection.zig-1
......@@ -28,7 +28,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 {
2828test "reflection: @field" {
2929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3030 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3231
3332 var f = Foo{
3433 .one = 42,
test/behavior/struct.zig-5
......@@ -68,7 +68,6 @@ const SmallStruct = struct {
6868
6969test "lower unnamed constants" {
7070 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
71 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7271
7372 var foo = SmallStruct{ .a = 1, .b = 255 };
7473 try expect(foo.first() == 1);
......@@ -395,7 +394,6 @@ test "packed struct" {
395394 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
396395 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
397396 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
398 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
399397
400398 var foo = APackedStruct{
401399 .x = 1,
......@@ -876,7 +874,6 @@ test "packed struct field passed to generic function" {
876874test "anonymous struct literal syntax" {
877875 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
878876 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
879 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
880877
881878 const S = struct {
882879 const Point = struct {
......@@ -1106,7 +1103,6 @@ test "packed struct with undefined initializers" {
11061103 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11071104 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11081105 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1109 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11101106
11111107 const S = struct {
11121108 const P = packed struct {
......@@ -1369,7 +1365,6 @@ test "store to comptime field" {
13691365test "struct field init value is size of the struct" {
13701366 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13711367 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1372 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13731368
13741369 const namespace = struct {
13751370 const S = extern struct {
test/behavior/this.zig-1
......@@ -27,7 +27,6 @@ test "this refer to module call private fn" {
2727test "this refer to container" {
2828 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3130
3231 var pt: Point(i32) = undefined;
3332 pt.x = 12;
test/behavior/union.zig-4
......@@ -2025,7 +2025,6 @@ test "inner struct initializer uses packed union layout" {
20252025
20262026test "extern union initialized via reintepreted struct field initializer" {
20272027 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2028 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20292028
20302029 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20312030
......@@ -2045,7 +2044,6 @@ test "extern union initialized via reintepreted struct field initializer" {
20452044
20462045test "packed union initialized via reintepreted struct field initializer" {
20472046 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2048 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20492047
20502048 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20512049
......@@ -2066,7 +2064,6 @@ test "packed union initialized via reintepreted struct field initializer" {
20662064
20672065test "store of comptime reinterpreted memory to extern union" {
20682066 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2069 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20702067
20712068 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20722069
......@@ -2089,7 +2086,6 @@ test "store of comptime reinterpreted memory to extern union" {
20892086
20902087test "store of comptime reinterpreted memory to packed union" {
20912088 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2092 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20932089
20942090 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
20952091