mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 16:24:51 +00:00
riscv: @atomicRmw
Now we generate debug undefined constants when the user asks for them to dedup across the function decl. This takes 2 instructions instead of 7 in the RISC-V backend. TODO, we need to dedupe across function decl boundaries.
This commit is contained in:
parent
ea084e9519
commit
0460572899
@ -117,8 +117,9 @@ const MCValue = union(enum) {
|
||||
/// No more references to this value remain.
|
||||
/// The payload is the value of scope_generation at the point where the death occurred
|
||||
dead: u32,
|
||||
/// The value is undefined.
|
||||
undef,
|
||||
/// The value is undefined. Contains a symbol index to an undefined constant. Null means
|
||||
/// set the undefined value via immediate instead of a load.
|
||||
undef: ?u32,
|
||||
/// A pointer-sized integer that fits in a register.
|
||||
/// If the type is a pointer, this is the pointer address in virtual address space.
|
||||
immediate: u64,
|
||||
@ -1045,6 +1046,7 @@ pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 {
|
||||
const required_features = [_]Target.riscv.Feature{
|
||||
.d,
|
||||
.m,
|
||||
.a,
|
||||
};
|
||||
|
||||
fn gen(func: *Func) !void {
|
||||
@ -1631,7 +1633,7 @@ fn computeFrameLayout(func: *Func) !FrameLayout {
|
||||
|
||||
// The total frame size is calculated by the amount of s registers you need to save * 8, as each
|
||||
// register is 8 bytes, the total allocation sizes, and 16 more register for the spilled ra and s0
|
||||
// register. Finally we align the frame size to the align of the base pointer.
|
||||
// register. Finally we align the frame size to the alignment of the base pointer.
|
||||
const args_frame_size = frame_size[@intFromEnum(FrameIndex.args_frame)];
|
||||
const spill_frame_size = frame_size[@intFromEnum(FrameIndex.spill_frame)];
|
||||
const call_frame_size = frame_size[@intFromEnum(FrameIndex.call_frame)];
|
||||
@ -2110,7 +2112,7 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
|
||||
});
|
||||
},
|
||||
.Int => {
|
||||
const size = ty.bitSize(zcu);
|
||||
const size = ty.bitSize(pt);
|
||||
if (!math.isPowerOfTwo(size))
|
||||
return func.fail("TODO: airNot non-pow 2 int size", .{});
|
||||
|
||||
@ -3249,7 +3251,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
|
||||
const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(eu_ty, pt));
|
||||
const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, pt));
|
||||
const err_off: i32 = @intCast(errUnionErrorOffset(pl_ty, pt));
|
||||
try func.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef);
|
||||
try func.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .{ .undef = null });
|
||||
const operand = try func.resolveInst(ty_op.operand);
|
||||
try func.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand);
|
||||
break :result .{ .load_frame = .{ .index = frame_index } };
|
||||
@ -5627,10 +5629,14 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
|
||||
.none,
|
||||
.dead,
|
||||
=> unreachable,
|
||||
.undef => {
|
||||
.undef => |sym_index| {
|
||||
if (!func.wantSafety())
|
||||
return;
|
||||
|
||||
if (sym_index) |index| {
|
||||
return func.genSetReg(ty, reg, .{ .load_symbol = .{ .sym = index } });
|
||||
}
|
||||
|
||||
switch (abi_size) {
|
||||
1 => return func.genSetReg(ty, reg, .{ .immediate = 0xAA }),
|
||||
2 => return func.genSetReg(ty, reg, .{ .immediate = 0xAAAA }),
|
||||
@ -5865,11 +5871,17 @@ fn genSetMem(
|
||||
.dead,
|
||||
.reserved_frame,
|
||||
=> unreachable,
|
||||
.undef => try func.genInlineMemset(
|
||||
dst_ptr_mcv,
|
||||
src_mcv,
|
||||
.{ .immediate = abi_size },
|
||||
),
|
||||
.undef => |sym_index| {
|
||||
if (sym_index) |index| {
|
||||
return func.genSetMem(base, disp, ty, .{ .load_symbol = .{ .sym = index } });
|
||||
}
|
||||
|
||||
try func.genInlineMemset(
|
||||
dst_ptr_mcv,
|
||||
src_mcv,
|
||||
.{ .immediate = abi_size },
|
||||
);
|
||||
},
|
||||
.register_offset,
|
||||
.memory,
|
||||
.indirect,
|
||||
@ -6069,12 +6081,82 @@ fn airCmpxchg(func: *Func, inst: Air.Inst.Index) !void {
|
||||
}
|
||||
|
||||
fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {
|
||||
_ = inst;
|
||||
return func.fail("TODO implement airCmpxchg for {}", .{func.target.cpu.arch});
|
||||
const zcu = func.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;
|
||||
|
||||
const op = extra.op();
|
||||
const order = extra.ordering();
|
||||
|
||||
const ptr_ty = func.typeOf(pl_op.operand);
|
||||
const ptr_mcv = try func.resolveInst(pl_op.operand);
|
||||
|
||||
const val_ty = func.typeOf(extra.operand);
|
||||
const val_size = val_ty.abiSize(func.pt);
|
||||
const val_mcv = try func.resolveInst(extra.operand);
|
||||
|
||||
if (!math.isPowerOfTwo(val_size))
|
||||
return func.fail("TODO: airAtomicRmw non-pow 2", .{});
|
||||
|
||||
switch (val_ty.zigTypeTag(zcu)) {
|
||||
.Int => {},
|
||||
inline .Bool, .Float, .Enum, .Pointer => |ty| return func.fail("TODO: airAtomicRmw {s}", .{@tagName(ty)}),
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
switch (val_size) {
|
||||
1, 2 => return func.fail("TODO: airAtomicRmw Int {}", .{val_size}),
|
||||
4, 8 => {},
|
||||
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);
|
||||
|
||||
const val_register, const val_lock = try func.promoteReg(val_ty, val_mcv);
|
||||
defer if (val_lock) |lock| func.register_manager.unlockReg(lock);
|
||||
|
||||
const result_mcv = try func.allocRegOrMem(val_ty, inst, true);
|
||||
assert(result_mcv == .register); // should fit into 8 bytes
|
||||
|
||||
const aq, const rl = switch (order) {
|
||||
.unordered => unreachable,
|
||||
.monotonic => .{ false, false },
|
||||
.acquire => .{ true, false },
|
||||
.release => .{ false, true },
|
||||
.acq_rel => .{ true, true },
|
||||
.seq_cst => .{ true, true },
|
||||
};
|
||||
|
||||
_ = try func.addInst(.{
|
||||
.tag = .pseudo,
|
||||
.ops = .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,
|
||||
} },
|
||||
});
|
||||
|
||||
return func.finishAir(inst, result_mcv, .{ pl_op.operand, extra.operand, .none });
|
||||
}
|
||||
|
||||
fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
|
||||
const zcu = func.bin_file.comp.module.?;
|
||||
const zcu = func.pt.zcu;
|
||||
const atomic_load = func.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
|
||||
const order: std.builtin.AtomicOrder = atomic_load.order;
|
||||
|
||||
@ -6083,6 +6165,7 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
|
||||
const ptr_mcv = try func.resolveInst(atomic_load.ptr);
|
||||
|
||||
const result_mcv = try func.allocRegOrMem(elem_ty, inst, true);
|
||||
assert(result_mcv == .register); // should be less than 8 bytes
|
||||
|
||||
if (order == .seq_cst) {
|
||||
_ = try func.addInst(.{
|
||||
@ -6535,19 +6618,40 @@ fn getResolvedInstValue(func: *Func, inst: Air.Inst.Index) *InstTracking {
|
||||
}
|
||||
|
||||
fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
|
||||
const pt = func.pt;
|
||||
const zcu = pt.zcu;
|
||||
const zcu = func.pt.zcu;
|
||||
const gpa = func.gpa;
|
||||
|
||||
const owner_decl_index = zcu.funcOwnerDeclIndex(func.func_index);
|
||||
const lf = func.bin_file;
|
||||
const src_loc = func.src_loc;
|
||||
|
||||
if (val.isUndef(zcu)) {
|
||||
const local_sym_index = lf.lowerUnnamedConst(func.pt, val, owner_decl_index) catch |err| {
|
||||
const msg = try ErrorMsg.create(gpa, src_loc, "lowering unnamed undefined constant failed: {s}", .{@errorName(err)});
|
||||
func.err_msg = msg;
|
||||
return error.CodegenFail;
|
||||
};
|
||||
switch (lf.tag) {
|
||||
.elf => {
|
||||
const elf_file = lf.cast(link.File.Elf).?;
|
||||
const local = elf_file.symbol(local_sym_index);
|
||||
return MCValue{ .undef = local.esym_index };
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
const result = try codegen.genTypedValue(
|
||||
func.bin_file,
|
||||
pt,
|
||||
func.src_loc,
|
||||
lf,
|
||||
func.pt,
|
||||
src_loc,
|
||||
val,
|
||||
zcu.funcOwnerDeclIndex(func.func_index),
|
||||
owner_decl_index,
|
||||
);
|
||||
const mcv: MCValue = switch (result) {
|
||||
.mcv => |mcv| switch (mcv) {
|
||||
.none => .none,
|
||||
.undef => .undef,
|
||||
.undef => unreachable,
|
||||
.load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
|
||||
.immediate => |imm| .{ .immediate = imm },
|
||||
.memory => |addr| .{ .memory = addr },
|
||||
|
||||
@ -28,7 +28,7 @@ const OpCode = enum(u7) {
|
||||
NONE = 0b00000000,
|
||||
};
|
||||
|
||||
const Fmt = enum(u2) {
|
||||
const FpFmt = enum(u2) {
|
||||
/// 32-bit single-precision
|
||||
S = 0b00,
|
||||
/// 64-bit double-precision
|
||||
@ -40,6 +40,11 @@ const Fmt = enum(u2) {
|
||||
Q = 0b11,
|
||||
};
|
||||
|
||||
const AmoWidth = enum(u3) {
|
||||
W = 0b010,
|
||||
D = 0b011,
|
||||
};
|
||||
|
||||
const Enc = struct {
|
||||
opcode: OpCode,
|
||||
|
||||
@ -49,11 +54,15 @@ const Enc = struct {
|
||||
funct3: u3,
|
||||
funct7: u7,
|
||||
},
|
||||
amo: struct {
|
||||
funct5: u5,
|
||||
width: AmoWidth,
|
||||
},
|
||||
/// funct5 + rm + fmt
|
||||
fmt: struct {
|
||||
funct5: u5,
|
||||
rm: u3,
|
||||
fmt: Fmt,
|
||||
fmt: FpFmt,
|
||||
},
|
||||
/// funct3
|
||||
f: struct {
|
||||
@ -202,6 +211,27 @@ pub const Mnemonic = enum {
|
||||
// MISC
|
||||
fence,
|
||||
|
||||
// AMO
|
||||
amoswapw,
|
||||
amoaddw,
|
||||
amoandw,
|
||||
amoorw,
|
||||
amoxorw,
|
||||
amomaxw,
|
||||
amominw,
|
||||
amomaxuw,
|
||||
amominuw,
|
||||
|
||||
amoswapd,
|
||||
amoaddd,
|
||||
amoandd,
|
||||
amoord,
|
||||
amoxord,
|
||||
amomaxd,
|
||||
amomind,
|
||||
amomaxud,
|
||||
amominud,
|
||||
|
||||
pub fn encoding(mnem: Mnemonic) Enc {
|
||||
return switch (mnem) {
|
||||
// zig fmt: off
|
||||
@ -379,7 +409,34 @@ pub const Mnemonic = enum {
|
||||
// MISC_MEM
|
||||
|
||||
.fence => .{ .opcode = .MISC_MEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
|
||||
|
||||
|
||||
// AMO
|
||||
|
||||
.amoaddw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00000 } } },
|
||||
.amoswapw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00001 } } },
|
||||
// LR.W
|
||||
// SC.W
|
||||
.amoxorw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00100 } } },
|
||||
.amoandw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01100 } } },
|
||||
.amoorw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01000 } } },
|
||||
.amominw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10000 } } },
|
||||
.amomaxw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10100 } } },
|
||||
.amominuw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11000 } } },
|
||||
.amomaxuw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11100 } } },
|
||||
|
||||
.amoaddd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00000 } } },
|
||||
.amoswapd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00001 } } },
|
||||
// LR.D
|
||||
// SC.D
|
||||
.amoxord => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00100 } } },
|
||||
.amoandd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01100 } } },
|
||||
.amoord => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01000 } } },
|
||||
.amomind => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10000 } } },
|
||||
.amomaxd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10100 } } },
|
||||
.amominud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11000 } } },
|
||||
.amomaxud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } },
|
||||
|
||||
|
||||
|
||||
// zig fmt: on
|
||||
};
|
||||
@ -395,6 +452,7 @@ pub const InstEnc = enum {
|
||||
U,
|
||||
J,
|
||||
fence,
|
||||
amo,
|
||||
/// extras that have unusual op counts
|
||||
system,
|
||||
|
||||
@ -526,21 +584,43 @@ pub const InstEnc = enum {
|
||||
|
||||
.fence,
|
||||
=> .fence,
|
||||
|
||||
.amoswapw,
|
||||
.amoaddw,
|
||||
.amoandw,
|
||||
.amoorw,
|
||||
.amoxorw,
|
||||
.amomaxw,
|
||||
.amominw,
|
||||
.amomaxuw,
|
||||
.amominuw,
|
||||
|
||||
.amoswapd,
|
||||
.amoaddd,
|
||||
.amoandd,
|
||||
.amoord,
|
||||
.amoxord,
|
||||
.amomaxd,
|
||||
.amomind,
|
||||
.amomaxud,
|
||||
.amominud,
|
||||
=> .amo,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn opsList(enc: InstEnc) [4]std.meta.FieldEnum(Operand) {
|
||||
pub fn opsList(enc: InstEnc) [5]std.meta.FieldEnum(Operand) {
|
||||
return switch (enc) {
|
||||
// zig fmt: off
|
||||
.R => .{ .reg, .reg, .reg, .none },
|
||||
.R4 => .{ .reg, .reg, .reg, .reg },
|
||||
.I => .{ .reg, .reg, .imm, .none },
|
||||
.S => .{ .reg, .reg, .imm, .none },
|
||||
.B => .{ .reg, .reg, .imm, .none },
|
||||
.U => .{ .reg, .imm, .none, .none },
|
||||
.J => .{ .reg, .imm, .none, .none },
|
||||
.system => .{ .none, .none, .none, .none },
|
||||
.fence => .{ .barrier, .barrier, .none, .none },
|
||||
.R => .{ .reg, .reg, .reg, .none, .none, },
|
||||
.R4 => .{ .reg, .reg, .reg, .reg, .none, },
|
||||
.I => .{ .reg, .reg, .imm, .none, .none, },
|
||||
.S => .{ .reg, .reg, .imm, .none, .none, },
|
||||
.B => .{ .reg, .reg, .imm, .none, .none, },
|
||||
.U => .{ .reg, .imm, .none, .none, .none, },
|
||||
.J => .{ .reg, .imm, .none, .none, .none, },
|
||||
.system => .{ .none, .none, .none, .none, .none, },
|
||||
.fence => .{ .barrier, .barrier, .none, .none, .none, },
|
||||
.amo => .{ .reg, .reg, .reg, .barrier, .barrier },
|
||||
// zig fmt: on
|
||||
};
|
||||
}
|
||||
@ -611,19 +691,29 @@ pub const Data = union(InstEnc) {
|
||||
pred: u4,
|
||||
_ignored: u4 = 0,
|
||||
},
|
||||
system: void,
|
||||
amo: packed struct {
|
||||
opcode: u7,
|
||||
rd: u5,
|
||||
funct3: u3,
|
||||
rs1: u5,
|
||||
rs2: u5,
|
||||
rl: bool,
|
||||
aq: bool,
|
||||
funct5: u5,
|
||||
},
|
||||
system: u32,
|
||||
|
||||
comptime {
|
||||
for (std.meta.fields(Data)) |field| {
|
||||
assert(@bitSizeOf(field.type) == 32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toU32(self: Data) u32 {
|
||||
return switch (self) {
|
||||
// zig fmt: off
|
||||
.R => |v| @bitCast(v),
|
||||
.R4 => |v| @bitCast(v),
|
||||
.I => |v| @bitCast(v),
|
||||
.S => |v| @bitCast(v),
|
||||
.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),
|
||||
.U => |v| @bitCast(v),
|
||||
.J => |v| @bitCast(v),
|
||||
.fence => |v| @bitCast(v),
|
||||
inline else => |v| @bitCast(v),
|
||||
.system => unreachable,
|
||||
// zig fmt: on
|
||||
};
|
||||
@ -792,6 +882,34 @@ pub const Data = union(InstEnc) {
|
||||
},
|
||||
};
|
||||
},
|
||||
.amo => {
|
||||
assert(ops.len == 5);
|
||||
|
||||
const rd = ops[0];
|
||||
const rs1 = ops[1];
|
||||
const rs2 = ops[2];
|
||||
const rl = ops[3];
|
||||
const aq = ops[4];
|
||||
|
||||
const ret: Data = .{
|
||||
.amo = .{
|
||||
.rd = rd.reg.encodeId(),
|
||||
.rs1 = rs1.reg.encodeId(),
|
||||
.rs2 = rs2.reg.encodeId(),
|
||||
|
||||
// TODO: https://github.com/ziglang/zig/issues/20113
|
||||
.rl = if (rl.barrier == .rl) true else false,
|
||||
.aq = if (aq.barrier == .aq) true else false,
|
||||
|
||||
.opcode = @intFromEnum(enc.opcode),
|
||||
.funct3 = @intFromEnum(enc.data.amo.width),
|
||||
.funct5 = enc.data.amo.funct5,
|
||||
},
|
||||
};
|
||||
|
||||
std.debug.print("ret: {}, {}", .{ ret.amo.rl, rl.barrier == .rl });
|
||||
return ret;
|
||||
},
|
||||
|
||||
else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}),
|
||||
}
|
||||
|
||||
@ -412,6 +412,32 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
|
||||
});
|
||||
},
|
||||
|
||||
.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: Encoding.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 },
|
||||
});
|
||||
},
|
||||
|
||||
else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),
|
||||
},
|
||||
}
|
||||
|
||||
@ -39,8 +39,6 @@ pub const Inst = struct {
|
||||
ecall,
|
||||
unimp,
|
||||
|
||||
fence,
|
||||
|
||||
add,
|
||||
addw,
|
||||
sub,
|
||||
@ -82,6 +80,8 @@ pub const Inst = struct {
|
||||
sh,
|
||||
sb,
|
||||
|
||||
fence,
|
||||
|
||||
// M extension
|
||||
mul,
|
||||
mulw,
|
||||
@ -136,6 +136,9 @@ pub const Inst = struct {
|
||||
fltd,
|
||||
fled,
|
||||
|
||||
/// A Extension Instructions
|
||||
amo,
|
||||
|
||||
/// A pseudo-instruction. Used for anything that isn't 1:1 with an
|
||||
/// assembly instruction.
|
||||
pseudo,
|
||||
@ -254,6 +257,16 @@ pub const Inst = struct {
|
||||
pred: Barrier,
|
||||
succ: Barrier,
|
||||
},
|
||||
|
||||
amo: struct {
|
||||
rd: Register,
|
||||
rs1: Register,
|
||||
rs2: Register,
|
||||
aq: Barrier,
|
||||
rl: Barrier,
|
||||
op: AmoOp,
|
||||
ty: Type,
|
||||
},
|
||||
};
|
||||
|
||||
pub const Ops = enum {
|
||||
@ -343,6 +356,9 @@ pub const Inst = struct {
|
||||
|
||||
/// IORW, IORW
|
||||
fence,
|
||||
|
||||
/// Ordering, Src, Addr, Dest
|
||||
pseudo_amo,
|
||||
};
|
||||
|
||||
// Make sure we don't accidentally make instructions bigger than expected.
|
||||
@ -379,9 +395,25 @@ pub const FrameLoc = struct {
|
||||
};
|
||||
|
||||
pub const Barrier = enum(u4) {
|
||||
// Fence
|
||||
r = 0b0001,
|
||||
w = 0b0010,
|
||||
rw = 0b0011,
|
||||
|
||||
// Amo
|
||||
none,
|
||||
aq,
|
||||
rl,
|
||||
};
|
||||
|
||||
pub const AmoOp = enum(u5) {
|
||||
SWAP,
|
||||
ADD,
|
||||
AND,
|
||||
OR,
|
||||
XOR,
|
||||
MAX,
|
||||
MIN,
|
||||
};
|
||||
|
||||
/// Returns the requested data, as well as the new index which is at the start of the
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
pub const Instruction = struct {
|
||||
encoding: Encoding,
|
||||
ops: [4]Operand = .{.none} ** 4,
|
||||
ops: [5]Operand = .{.none} ** 5,
|
||||
|
||||
pub const Operand = union(enum) {
|
||||
none,
|
||||
@ -12,16 +12,18 @@ pub const Instruction = struct {
|
||||
|
||||
pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction {
|
||||
const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse {
|
||||
std.log.err("no encoding found for: {s} [{s} {s} {s}]", .{
|
||||
std.log.err("no encoding found for: {s} [{s} {s} {s} {s} {s}]", .{
|
||||
@tagName(mnemonic),
|
||||
@tagName(if (ops.len > 0) ops[0] else .none),
|
||||
@tagName(if (ops.len > 1) ops[1] else .none),
|
||||
@tagName(if (ops.len > 2) ops[2] else .none),
|
||||
@tagName(if (ops.len > 3) ops[3] else .none),
|
||||
@tagName(if (ops.len > 4) ops[4] else .none),
|
||||
});
|
||||
return error.InvalidInstruction;
|
||||
};
|
||||
|
||||
var result_ops: [4]Operand = .{.none} ** 4;
|
||||
var result_ops: [5]Operand = .{.none} ** 5;
|
||||
@memcpy(result_ops[0..ops.len], ops);
|
||||
|
||||
return .{
|
||||
|
||||
@ -987,8 +987,9 @@ pub fn genTypedValue(
|
||||
|
||||
log.debug("genTypedValue: val = {}", .{val.fmtValue(pt, null)});
|
||||
|
||||
if (val.isUndef(zcu))
|
||||
if (val.isUndef(zcu)) {
|
||||
return GenResult.mcv(.undef);
|
||||
}
|
||||
|
||||
const owner_decl = zcu.declPtr(owner_decl_index);
|
||||
const namespace = zcu.namespacePtr(owner_decl.src_namespace);
|
||||
|
||||
@ -540,8 +540,8 @@ inline fn isGlobal(index: Symbol.Index) bool {
|
||||
|
||||
pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index {
|
||||
const actual_index = index & symbol_mask;
|
||||
if (isGlobal(index)) return self.global_symbols.items[actual_index];
|
||||
return self.local_symbols.items[actual_index];
|
||||
if (isGlobal(index)) return self.globals()[actual_index];
|
||||
return self.locals()[actual_index];
|
||||
}
|
||||
|
||||
pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
|
||||
@ -1334,11 +1334,15 @@ fn lowerConst(
|
||||
|
||||
const sym_index = try self.addAtom(elf_file);
|
||||
|
||||
const res = try codegen.generateSymbol(&elf_file.base, pt, src_loc, val, &code_buffer, .{
|
||||
.none = {},
|
||||
}, .{
|
||||
.parent_atom_index = sym_index,
|
||||
});
|
||||
const res = try codegen.generateSymbol(
|
||||
&elf_file.base,
|
||||
pt,
|
||||
src_loc,
|
||||
val,
|
||||
&code_buffer,
|
||||
.{ .none = {} },
|
||||
.{ .parent_atom_index = sym_index },
|
||||
);
|
||||
const code = switch (res) {
|
||||
.ok => code_buffer.items,
|
||||
.fail => |em| return .{ .fail = em },
|
||||
|
||||
@ -188,21 +188,6 @@ test "atomic store" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
var x: u32 = 0;
|
||||
@atomicStore(u32, &x, 1, .seq_cst);
|
||||
try expect(@atomicLoad(u32, &x, .seq_cst) == 1);
|
||||
@atomicStore(u32, &x, 12345678, .seq_cst);
|
||||
try expect(@atomicLoad(u32, &x, .seq_cst) == 12345678);
|
||||
}
|
||||
|
||||
test "atomic store comptime" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
try comptime testAtomicStore();
|
||||
try testAtomicStore();
|
||||
@ -451,7 +436,6 @@ test "return @atomicStore, using it as a void value" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
const A = struct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user