diff options
| author | David Rubin <daviru007@icloud.com> | 2024-07-25 23:01:44 -0700 |
|---|---|---|
| committer | David Rubin <daviru007@icloud.com> | 2024-07-26 04:19:57 -0700 |
| commit | 7ff5709e1b04de4c33988ce6a27bc593dcf20f63 (patch) | |
| tree | da08f073bec966042a0815579b5b68ceb9399c29 | |
| parent | a1f6a8ef90f0778e4fc5d314eeb1f0a0a93fa53a (diff) | |
| download | zig-7ff5709e1b04de4c33988ce6a27bc593dcf20f63.tar.gz zig-7ff5709e1b04de4c33988ce6a27bc593dcf20f63.zip | |
riscv: implement `lr/sr` loop logic for non-native atomics
| -rw-r--r-- | lib/std/start.zig | 6 | ||||
| -rw-r--r-- | src/arch/riscv64/CodeGen.zig | 166 | ||||
| -rw-r--r-- | src/arch/riscv64/Lower.zig | 49 | ||||
| -rw-r--r-- | src/arch/riscv64/Mir.zig | 6 | ||||
| -rw-r--r-- | src/arch/riscv64/abi.zig | 5 | ||||
| -rw-r--r-- | src/arch/riscv64/encoding.zig | 12 | ||||
| -rw-r--r-- | src/arch/riscv64/mnem.zig | 7 |
7 files changed, 138 insertions, 113 deletions
diff --git a/lib/std/start.zig b/lib/std/start.zig index f911550f08..aeefbaffc0 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -478,10 +478,8 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { std.os.argv = argv[0..argc]; std.os.environ = envp; - if (builtin.zig_backend != .stage2_riscv64) { - std.debug.maybeEnableSegfaultHandler(); - maybeIgnoreSigpipe(); - } + std.debug.maybeEnableSegfaultHandler(); + maybeIgnoreSigpipe(); return callMain(); } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index be17fd8aae..e0a0033d15 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -4717,14 +4717,11 @@ fn airFence(func: *Func, inst: Air.Inst.Index) !void { }; _ = try func.addInst(.{ - .tag = .pseudo_fence, - .data = .{ - .fence = .{ - .pred = pred, - .succ = succ, - .fm = if (order == .acq_rel) .tso else .none, - }, - }, + .tag = if (order == .acq_rel) .fencetso else .fence, + .data = .{ .fence = .{ + .pred = pred, + .succ = succ, + } }, }); return func.finishAirBookkeeping(); } @@ -5278,12 +5275,12 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC .dead, .undef, .immediate, - .register_pair, .register_offset, .lea_frame, .lea_symbol, .reserved_frame, .air_ref, + .register_pair, => unreachable, .register => |opt_reg| { @@ -7109,6 +7106,7 @@ fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void { fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { const pt = func.pt; + const zcu = pt.zcu; const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data; @@ -7131,11 +7129,11 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { else => unreachable, } - switch (val_size) { - 1, 2 => return func.fail("TODO: airAtomicRmw {s} Int {}", .{ @tagName(op), val_size }), - 4, 8 => {}, + const method: enum { amo, loop } = switch (val_size) { + 1, 2 => .loop, + 4, 8 => .amo, else => unreachable, - } + }; const ptr_register, const ptr_lock = try func.promoteReg(ptr_ty, ptr_mcv); defer if (ptr_lock) |lock| func.register_manager.unlockReg(lock); @@ -7145,6 +7143,7 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { const result_mcv = try func.allocRegOrMem(val_ty, inst, true); assert(result_mcv == .register); // should fit into 8 bytes + const result_reg = result_mcv.register; const aq, const rl = switch (order) { .unordered => unreachable, @@ -7155,28 +7154,96 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { .seq_cst => .{ true, true }, }; - _ = try func.addInst(.{ - .tag = .pseudo_amo, - .data = .{ .amo = .{ - .rd = result_mcv.register, - .rs1 = ptr_register, - .rs2 = val_register, - .aq = if (aq) .aq else .none, - .rl = if (rl) .rl else .none, - .op = switch (op) { - .Xchg => .SWAP, - .Add => .ADD, - .Sub => return func.fail("TODO: airAtomicRmw SUB", .{}), - .And => .AND, - .Nand => return func.fail("TODO: airAtomicRmw NAND", .{}), - .Or => .OR, - .Xor => .XOR, - .Max => .MAX, - .Min => .MIN, - }, - .ty = val_ty, - } }, - }); + switch (method) { + .amo => { + const is_d = val_ty.abiSize(pt) == 8; + const is_un = val_ty.isUnsignedInt(zcu); + + const mnem: Mnemonic = switch (op) { + // zig fmt: off + .Xchg => if (is_d) .amoswapd else .amoswapw, + .Add => if (is_d) .amoaddd else .amoaddw, + .And => if (is_d) .amoandd else .amoandw, + .Or => if (is_d) .amoord else .amoorw, + .Xor => if (is_d) .amoxord else .amoxorw, + .Max => if (is_d) if (is_un) .amomaxud else .amomaxd else if (is_un) .amomaxuw else .amomaxw, + .Min => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw, + else => return func.fail("TODO: airAtomicRmw amo {s}", .{@tagName(op)}), + // zig fmt: on + }; + + _ = try func.addInst(.{ + .tag = mnem, + .data = .{ .amo = .{ + .rd = result_reg, + .rs1 = ptr_register, + .rs2 = val_register, + .aq = if (aq) .aq else .none, + .rl = if (rl) .rl else .none, + } }, + }); + }, + .loop => { + // where we'll jump back when the sc fails + const jump_back = try func.addInst(.{ + .tag = .lrw, + .data = .{ .amo = .{ + .rd = result_reg, + .rs1 = ptr_register, + .rs2 = .zero, + .aq = if (aq) .aq else .none, + .rl = if (rl) .rl else .none, + } }, + }); + + const after_reg, const after_lock = try func.allocReg(.int); + defer func.register_manager.unlockReg(after_lock); + + switch (op) { + .Add => { + _ = try func.genBinOp( + .add, + .{ .register = result_reg }, + val_ty, + .{ .register = val_register }, + val_ty, + after_reg, + ); + }, + .Sub => { + _ = try func.genBinOp( + .sub, + .{ .register = result_reg }, + val_ty, + .{ .register = val_register }, + val_ty, + after_reg, + ); + }, + else => return func.fail("TODO: airAtomicRmw loop {s}", .{@tagName(op)}), + } + + _ = try func.addInst(.{ + .tag = .scw, + .data = .{ .amo = .{ + .rd = after_reg, + .rs1 = ptr_register, + .rs2 = after_reg, + .aq = if (aq) .aq else .none, + .rl = if (rl) .rl else .none, + } }, + }); + + _ = try func.addInst(.{ + .tag = .bne, + .data = .{ .b_type = .{ + .inst = jump_back, + .rs1 = after_reg, + .rs2 = .zero, + } }, + }); + }, + } return func.finishAir(inst, result_mcv, .{ pl_op.operand, extra.operand, .none }); } @@ -7199,11 +7266,10 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void { if (order == .seq_cst) { _ = try func.addInst(.{ - .tag = .pseudo_fence, + .tag = .fence, .data = .{ .fence = .{ .pred = .rw, .succ = .rw, - .fm = .none, } }, }); } @@ -7217,14 +7283,11 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void { // Make sure all previous reads happen before any reading or writing accurs. .seq_cst, .acquire => { _ = try func.addInst(.{ - .tag = .pseudo_fence, - .data = .{ - .fence = .{ - .pred = .r, - .succ = .rw, - .fm = .none, - }, - }, + .tag = .fence, + .data = .{ .fence = .{ + .pred = .r, + .succ = .rw, + } }, }); }, else => unreachable, @@ -7249,14 +7312,11 @@ fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOr .unordered, .monotonic => {}, .release, .seq_cst => { _ = try func.addInst(.{ - .tag = .pseudo_fence, - .data = .{ - .fence = .{ - .pred = .rw, - .succ = .w, - .fm = .none, - }, - }, + .tag = .fence, + .data = .{ .fence = .{ + .pred = .rw, + .succ = .w, + } }, }); }, else => unreachable, diff --git a/src/arch/riscv64/Lower.zig b/src/arch/riscv64/Lower.zig index a3b68b85ba..370731c0ae 100644 --- a/src/arch/riscv64/Lower.zig +++ b/src/arch/riscv64/Lower.zig @@ -446,44 +446,6 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { .{ .imm = Immediate.s(0) }, }); }, - - .pseudo_amo => { - const amo = inst.data.amo; - const is_d = amo.ty.abiSize(pt) == 8; - const is_un = amo.ty.isUnsignedInt(pt.zcu); - - const mnem: Mnemonic = switch (amo.op) { - // zig fmt: off - .SWAP => if (is_d) .amoswapd else .amoswapw, - .ADD => if (is_d) .amoaddd else .amoaddw, - .AND => if (is_d) .amoandd else .amoandw, - .OR => if (is_d) .amoord else .amoorw, - .XOR => if (is_d) .amoxord else .amoxorw, - .MAX => if (is_d) if (is_un) .amomaxud else .amomaxd else if (is_un) .amomaxuw else .amomaxw, - .MIN => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw, - // zig fmt: on - }; - - try lower.emit(mnem, &.{ - .{ .reg = inst.data.amo.rd }, - .{ .reg = inst.data.amo.rs1 }, - .{ .reg = inst.data.amo.rs2 }, - .{ .barrier = inst.data.amo.rl }, - .{ .barrier = inst.data.amo.aq }, - }); - }, - - .pseudo_fence => { - const fence = inst.data.fence; - - try lower.emit(switch (fence.fm) { - .tso => .fencetso, - .none => .fence, - }, &.{ - .{ .barrier = fence.succ }, - .{ .barrier = fence.pred }, - }); - }, } return .{ @@ -524,6 +486,17 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { .{ .reg = csr.rs1 }, .{ .reg = csr.rd }, }, + .amo => |amo| &.{ + .{ .reg = amo.rd }, + .{ .reg = amo.rs1 }, + .{ .reg = amo.rs2 }, + .{ .barrier = amo.rl }, + .{ .barrier = amo.aq }, + }, + .fence => |fence| &.{ + .{ .barrier = fence.succ }, + .{ .barrier = fence.pred }, + }, else => return lower.fail("TODO: generic lower {s}", .{@tagName(inst.data)}), }); } diff --git a/src/arch/riscv64/Mir.zig b/src/arch/riscv64/Mir.zig index bb4fd28536..2ae62fd9b2 100644 --- a/src/arch/riscv64/Mir.zig +++ b/src/arch/riscv64/Mir.zig @@ -73,10 +73,6 @@ pub const Inst = struct { fence: struct { pred: Barrier, succ: Barrier, - fm: enum { - none, - tso, - }, }, amo: struct { rd: Register, @@ -84,8 +80,6 @@ pub const Inst = struct { rs2: Register, aq: Barrier, rl: Barrier, - op: AmoOp, - ty: Type, }, csr: struct { csr: CSR, diff --git a/src/arch/riscv64/abi.zig b/src/arch/riscv64/abi.zig index baed5cc68c..9f0a39280d 100644 --- a/src/arch/riscv64/abi.zig +++ b/src/arch/riscv64/abi.zig @@ -125,10 +125,7 @@ pub fn classifySystem(ty: Type, pt: Zcu.PerThread) [8]SystemClass { result[0] = .integer; return result; } - result[0] = .integer; - if (ty.optionalChild(zcu).abiSize(pt) == 0) return result; - result[1] = .integer; - return result; + return memory_class; }, .Int, .Enum, .ErrorSet => { const int_bits = ty.intInfo(pt.zcu).bits; diff --git a/src/arch/riscv64/encoding.zig b/src/arch/riscv64/encoding.zig index 7c1bd274e0..61ba0132f4 100644 --- a/src/arch/riscv64/encoding.zig +++ b/src/arch/riscv64/encoding.zig @@ -353,6 +353,7 @@ pub const Lir = struct { // BRANCH .beq => .{ .opcode = .BRANCH, .format = .B, .data = .{ .f = .{ .funct3 = 0b000 } } }, + .bne => .{ .opcode = .BRANCH, .format = .B, .data = .{ .f = .{ .funct3 = 0b001 } } }, // SYSTEM @@ -378,8 +379,8 @@ pub const Lir = struct { .amoaddw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00000 } } }, .amoswapw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00001 } } }, - // LR.W - // SC.W + .lrw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00010 } } }, + .scw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00011 } } }, .amoxorw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00100 } } }, .amoandw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01100 } } }, .amoorw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01000 } } }, @@ -388,10 +389,11 @@ pub const Lir = struct { .amominuw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11000 } } }, .amomaxuw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11100 } } }, + .amoaddd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00000 } } }, .amoswapd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00001 } } }, - // LR.D - // SC.D + .lrd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00010 } } }, + .scd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00011 } } }, .amoxord => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00100 } } }, .amoandd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01100 } } }, .amoord => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01000 } } }, @@ -434,8 +436,6 @@ pub const Lir = struct { .pseudo_compare, .pseudo_not, .pseudo_extern_fn_reloc, - .pseudo_fence, - .pseudo_amo, .nop, => std.debug.panic("lir: didn't catch pseudo {s}", .{@tagName(mnem)}), // zig fmt: on diff --git a/src/arch/riscv64/mnem.zig b/src/arch/riscv64/mnem.zig index 7f0fd3475f..926ee19ba9 100644 --- a/src/arch/riscv64/mnem.zig +++ b/src/arch/riscv64/mnem.zig @@ -40,6 +40,7 @@ pub const Mnemonic = enum(u16) { jal, beq, + bne, // Memory lui, @@ -178,6 +179,8 @@ pub const Mnemonic = enum(u16) { fence, fencetso, + lrw, + scw, amoswapw, amoaddw, amoandw, @@ -188,6 +191,8 @@ pub const Mnemonic = enum(u16) { amomaxuw, amominuw, + lrd, + scd, amoswapd, amoaddd, amoandd, @@ -237,8 +242,6 @@ pub const Mnemonic = enum(u16) { pseudo_compare, pseudo_not, pseudo_extern_fn_reloc, - pseudo_fence, - pseudo_amo, }; pub const Pseudo = enum(u8) { |
