authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-06-01 00:42:29-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-07-14 23:02:33-07:00
log3e73f37d0a371276c534240ee2d26cbf4b3a0033
treeb0736a37d79066c8cb0649107fcb14db3ef260e7
parent7a02878f4e1ff18275e61db7450fb3e12ee1926e
signaturelock-open Commit is signed but in an unrecognized format.

riscv: implement `@fence`


6 files changed, 75 insertions(+), 36 deletions(-)

src/arch/riscv64/CodeGen.zig+32-10
......@@ -1318,7 +1318,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
13181318 .breakpoint => try func.airBreakpoint(),
13191319 .ret_addr => try func.airRetAddr(inst),
13201320 .frame_addr => try func.airFrameAddress(inst),
1321 .fence => try func.airFence(),
1321 .fence => try func.airFence(inst),
13221322 .cond_br => try func.airCondBr(inst),
13231323 .dbg_stmt => try func.airDbgStmt(inst),
13241324 .fptrunc => try func.airFptrunc(inst),
......@@ -4238,9 +4238,28 @@ fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {
42384238 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });
42394239}
42404240
4241fn airFence(func: *Func) !void {
4242 return func.fail("TODO implement fence() for {}", .{func.target.cpu.arch});
4243 //return func.finishAirBookkeeping();
4241fn airFence(func: *Func, inst: Air.Inst.Index) !void {
4242 const order = func.air.instructions.items(.data)[@intFromEnum(inst)].fence;
4243 const pred: Mir.Barrier, const succ: Mir.Barrier = switch (order) {
4244 .unordered, .monotonic => unreachable,
4245 .acquire => .{ .r, .rw },
4246 .release => .{ .rw, .r },
4247 .acq_rel => .{ .rw, .rw },
4248 .seq_cst => .{ .rw, .rw },
4249 };
4250
4251 _ = try func.addInst(.{
4252 .tag = .pseudo,
4253 .ops = .pseudo_fence,
4254 .data = .{
4255 .fence = .{
4256 .pred = pred,
4257 .succ = succ,
4258 .fm = if (order == .acq_rel) .tso else .none,
4259 },
4260 },
4261 });
4262 return func.finishAirBookkeeping();
42444263}
42454264
42464265fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
......@@ -6264,12 +6283,13 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
62646283
62656284 if (order == .seq_cst) {
62666285 _ = try func.addInst(.{
6267 .tag = .fence,
6268 .ops = .fence,
6286 .tag = .pseudo,
6287 .ops = .pseudo_fence,
62696288 .data = .{
62706289 .fence = .{
62716290 .pred = .rw,
62726291 .succ = .rw,
6292 .fm = .none,
62736293 },
62746294 },
62756295 });
......@@ -6284,12 +6304,13 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
62846304 // Make sure all previous reads happen before any reading or writing accurs.
62856305 .seq_cst, .acquire => {
62866306 _ = try func.addInst(.{
6287 .tag = .fence,
6288 .ops = .fence,
6307 .tag = .pseudo,
6308 .ops = .pseudo_fence,
62896309 .data = .{
62906310 .fence = .{
62916311 .pred = .r,
62926312 .succ = .rw,
6313 .fm = .none,
62936314 },
62946315 },
62956316 });
......@@ -6313,12 +6334,13 @@ fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOr
63136334 .unordered, .monotonic => {},
63146335 .release, .seq_cst => {
63156336 _ = try func.addInst(.{
6316 .tag = .fence,
6317 .ops = .fence,
6337 .tag = .pseudo,
6338 .ops = .pseudo_fence,
63186339 .data = .{
63196340 .fence = .{
63206341 .pred = .rw,
63216342 .succ = .w,
6343 .fm = .none,
63226344 },
63236345 },
63246346 });
src/arch/riscv64/Encoding.zig+24-15
......@@ -45,6 +45,11 @@ const AmoWidth = enum(u3) {
4545 D = 0b011,
4646};
4747
48const FenceMode = enum(u4) {
49 none = 0b0000,
50 tso = 0b1000,
51};
52
4853const Enc = struct {
4954 opcode: OpCode,
5055
......@@ -58,6 +63,10 @@ const Enc = struct {
5863 funct5: u5,
5964 width: AmoWidth,
6065 },
66 fence: struct {
67 funct3: u3,
68 fm: FenceMode,
69 },
6170 /// funct5 + rm + fmt
6271 fmt: struct {
6372 funct5: u5,
......@@ -210,6 +219,7 @@ pub const Mnemonic = enum {
210219
211220 // MISC
212221 fence,
222 fencetso,
213223
214224 // AMO
215225 amoswapw,
......@@ -406,9 +416,12 @@ pub const Mnemonic = enum {
406416
407417 .unimp => .{ .opcode = .NONE, .data = .{ .f = .{ .funct3 = 0b000 } } },
408418
419
409420 // MISC_MEM
410421
411 .fence => .{ .opcode = .MISC_MEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
422 .fence => .{ .opcode = .MISC_MEM, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .none } } },
423 .fencetso => .{ .opcode = .MISC_MEM, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .tso } } },
424
412425
413426 // AMO
414427
......@@ -437,7 +450,6 @@ pub const Mnemonic = enum {
437450 .amomaxud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } },
438451
439452
440
441453 // zig fmt: on
442454 };
443455 }
......@@ -583,6 +595,7 @@ pub const InstEnc = enum {
583595 => .system,
584596
585597 .fence,
598 .fencetso,
586599 => .fence,
587600
588601 .amoswapw,
......@@ -689,7 +702,7 @@ pub const Data = union(InstEnc) {
689702 rs1: u5 = 0,
690703 succ: u4,
691704 pred: u4,
692 _ignored: u4 = 0,
705 fm: u4,
693706 },
694707 amo: packed struct {
695708 opcode: u7,
......@@ -711,11 +724,9 @@ pub const Data = union(InstEnc) {
711724
712725 pub fn toU32(self: Data) u32 {
713726 return switch (self) {
714 // zig fmt: off
715 .B => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.imm11)) << 7) + (@as(u32, @intCast(v.imm1_4)) << 8) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.rs2)) << 20) + (@as(u32, @intCast(v.imm5_10)) << 25) + (@as(u32, @intCast(v.imm12)) << 31),
727 .fence => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.rd)) << 7) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.succ)) << 20) + (@as(u32, @intCast(v.pred)) << 24) + (@as(u32, @intCast(v.fm)) << 28),
716728 inline else => |v| @bitCast(v),
717729 .system => unreachable,
718 // zig fmt: on
719730 };
720731 }
721732
......@@ -869,16 +880,17 @@ pub const Data = union(InstEnc) {
869880 .fence => {
870881 assert(ops.len == 2);
871882
872 const succ = ops[0];
873 const pred = ops[1];
883 const succ = ops[0].barrier;
884 const pred = ops[1].barrier;
874885
875886 return .{
876887 .fence = .{
877 .succ = @intFromEnum(succ.barrier),
878 .pred = @intFromEnum(pred.barrier),
888 .succ = @intFromEnum(succ),
889 .pred = @intFromEnum(pred),
879890
880891 .opcode = @intFromEnum(enc.opcode),
881 .funct3 = enc.data.f.funct3,
892 .funct3 = enc.data.fence.funct3,
893 .fm = @intFromEnum(enc.data.fence.fm),
882894 },
883895 };
884896 },
......@@ -891,7 +903,7 @@ pub const Data = union(InstEnc) {
891903 const rl = ops[3];
892904 const aq = ops[4];
893905
894 const ret: Data = .{
906 return .{
895907 .amo = .{
896908 .rd = rd.reg.encodeId(),
897909 .rs1 = rs1.reg.encodeId(),
......@@ -906,9 +918,6 @@ pub const Data = union(InstEnc) {
906918 .funct5 = enc.data.amo.funct5,
907919 },
908920 };
909
910 std.debug.print("ret: {}, {}", .{ ret.amo.rl, rl.barrier == .rl });
911 return ret;
912921 },
913922
914923 else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}),
src/arch/riscv64/Lower.zig+12-4
......@@ -443,6 +443,18 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
443443 });
444444 },
445445
446 .pseudo_fence => {
447 const fence = inst.data.fence;
448
449 try lower.emit(switch (fence.fm) {
450 .tso => .fencetso,
451 .none => .fence,
452 }, &.{
453 .{ .barrier = fence.succ },
454 .{ .barrier = fence.pred },
455 });
456 },
457
446458 else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),
447459 },
448460 }
......@@ -485,10 +497,6 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
485497 .{ .reg = inst.data.r_type.rs1 },
486498 .{ .reg = inst.data.r_type.rs2 },
487499 },
488 .fence => &.{
489 .{ .barrier = inst.data.fence.succ },
490 .{ .barrier = inst.data.fence.pred },
491 },
492500 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),
493501 });
494502}
src/arch/riscv64/Mir.zig+7-5
......@@ -80,8 +80,6 @@ pub const Inst = struct {
8080 sh,
8181 sb,
8282
83 fence,
84
8583 // M extension
8684 mul,
8785 mulw,
......@@ -256,6 +254,10 @@ pub const Inst = struct {
256254 fence: struct {
257255 pred: Barrier,
258256 succ: Barrier,
257 fm: enum {
258 none,
259 tso,
260 },
259261 },
260262
261263 amo: struct {
......@@ -355,7 +357,7 @@ pub const Inst = struct {
355357 pseudo_extern_fn_reloc,
356358
357359 /// IORW, IORW
358 fence,
360 pseudo_fence,
359361
360362 /// Ordering, Src, Addr, Dest
361363 pseudo_amo,
......@@ -396,8 +398,8 @@ pub const FrameLoc = struct {
396398
397399pub const Barrier = enum(u4) {
398400 // Fence
399 r = 0b0001,
400 w = 0b0010,
401 w = 0b0001,
402 r = 0b0010,
401403 rw = 0b0011,
402404
403405 // Amo
test/behavior/atomics.zig-1
......@@ -42,7 +42,6 @@ test "fence" {
4242 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4343 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4444 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
45 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4645
4746 var x: i32 = 1234;
4847 @fence(.seq_cst);
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1
......@@ -11,7 +11,6 @@ test {
1111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1313 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
14 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1514
1615 var val: u8 = undefined;
1716 try testing.expectEqual({}, @atomicStore(u8, &val, 0, .unordered));