Commit 1467590e40
Changed files (4)
src
arch
src/arch/sparcv9/bits.zig
@@ -979,6 +979,38 @@ pub const Instruction = union(enum) {
};
}
+ pub fn ldub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b11, 0b00_0001, rs1, rs2, rd),
+ i13 => format3b(0b11, 0b00_0001, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn lduh(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b11, 0b00_0010, rs1, rs2, rd),
+ i13 => format3b(0b11, 0b00_0010, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn lduw(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b11, 0b00_0000, rs1, rs2, rd),
+ i13 => format3b(0b11, 0b00_0000, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
+ pub fn ldx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
+ return switch (s2) {
+ Register => format3a(0b11, 0b00_1011, rs1, rs2, rd),
+ i13 => format3b(0b11, 0b00_1011, rs1, rs2, rd),
+ else => unreachable,
+ };
+ }
+
pub fn nop() Instruction {
return sethi(0, .g0);
}
src/arch/sparcv9/CodeGen.zig
@@ -193,6 +193,43 @@ const CallMCValues = struct {
}
};
+const BigTomb = struct {
+ function: *Self,
+ inst: Air.Inst.Index,
+ tomb_bits: Liveness.Bpi,
+ big_tomb_bits: u32,
+ bit_index: usize,
+
+ fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void {
+ const this_bit_index = bt.bit_index;
+ bt.bit_index += 1;
+
+ const op_int = @enumToInt(op_ref);
+ if (op_int < Air.Inst.Ref.typed_value_map.len) return;
+ const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
+
+ if (this_bit_index < Liveness.bpi - 1) {
+ const dies = @truncate(u1, bt.tomb_bits >> @intCast(Liveness.OperandInt, this_bit_index)) != 0;
+ if (!dies) return;
+ } else {
+ const big_bit_index = @intCast(u5, this_bit_index - (Liveness.bpi - 1));
+ const dies = @truncate(u1, bt.big_tomb_bits >> big_bit_index) != 0;
+ if (!dies) return;
+ }
+ bt.function.processDeath(op_index);
+ }
+
+ fn finishAir(bt: *BigTomb, result: MCValue) void {
+ const is_used = !bt.function.liveness.isUnused(bt.inst);
+ if (is_used) {
+ log.debug("%{d} => {}", .{ bt.inst, result });
+ const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
+ branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);
+ }
+ bt.function.finishAirBookkeeping();
+ }
+};
+
pub fn generate(
bin_file: *link.File,
src_loc: Module.SrcLoc,
@@ -684,8 +721,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, buf);
}
- @panic("TODO implement asm return");
- //return self.fail("TODO implement asm return for {}", .{self.target.cpu.arch});
+ var bt = try self.iterateBigTomb(inst, outputs.len + inputs.len);
+ for (outputs) |output| {
+ if (output == .none) continue;
+
+ bt.feed(output);
+ }
+ for (inputs) |input| {
+ bt.feed(input);
+ }
+ return bt.finishAir(result);
}
fn airArg(self: *Self, inst: Air.Inst.Index) !void {
@@ -1071,13 +1116,65 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
self.finishAirBookkeeping();
}
-fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, off: i13, abi_size: u64) !void {
- _ = value_reg;
- _ = addr_reg;
- _ = off;
+fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_type: type, off: off_type, abi_size: u64) !void {
+ assert(off_type == Register or off_type == i13);
+
+ const is_imm = (off_type == i13);
+ const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off };
switch (abi_size) {
- 1, 2, 4, 8 => return self.fail("TODO: A.27 Load Integer", .{}),
+ 1 => {
+ _ = try self.addInst(.{
+ .tag = .ldub,
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = is_imm,
+ .rd = value_reg,
+ .rs1 = addr_reg,
+ .rs2_or_imm = rs2_or_imm,
+ },
+ },
+ });
+ },
+ 2 => {
+ _ = try self.addInst(.{
+ .tag = .lduh,
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = is_imm,
+ .rd = value_reg,
+ .rs1 = addr_reg,
+ .rs2_or_imm = rs2_or_imm,
+ },
+ },
+ });
+ },
+ 4 => {
+ _ = try self.addInst(.{
+ .tag = .lduw,
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = is_imm,
+ .rd = value_reg,
+ .rs1 = addr_reg,
+ .rs2_or_imm = rs2_or_imm,
+ },
+ },
+ });
+ },
+ 8 => {
+ _ = try self.addInst(.{
+ .tag = .ldx,
+ .data = .{
+ .arithmetic_3op = .{
+ .is_imm = is_imm,
+ .rd = value_reg,
+ .rs1 = addr_reg,
+ .rs2_or_imm = rs2_or_imm,
+ },
+ },
+ });
+ },
3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}),
else => unreachable,
}
@@ -1226,12 +1323,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
// The value is in memory at a hard-coded address.
// If the type is a pointer, it means the pointer address is at this memory location.
try self.genSetReg(ty, reg, .{ .immediate = addr });
- try self.genLoad(reg, reg, 0, ty.abiSize(self.target.*));
+ try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*));
},
.stack_offset => |off| {
const simm13 = math.cast(u12, off) catch
return self.fail("TODO larger stack offsets", .{});
- try self.genLoad(reg, .sp, simm13, ty.abiSize(self.target.*));
+ try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*));
},
}
}
@@ -1269,14 +1366,10 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
return MCValue{ .undef = {} };
if (typed_value.val.castTag(.decl_ref)) |payload| {
- _ = payload;
- return self.fail("TODO implement lowerDeclRef non-mut", .{});
- // return self.lowerDeclRef(typed_value, payload.data);
+ return self.lowerDeclRef(typed_value, payload.data);
}
if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
- _ = payload;
- return self.fail("TODO implement lowerDeclRef mut", .{});
- // return self.lowerDeclRef(typed_value, payload.data.decl);
+ return self.lowerDeclRef(typed_value, payload.data.decl);
}
const target = self.target.*;
@@ -1315,6 +1408,39 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
}
}
+fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigTomb {
+ try self.ensureProcessDeathCapacity(operand_count + 1);
+ return BigTomb{
+ .function = self,
+ .inst = inst,
+ .tomb_bits = self.liveness.getTombBits(inst),
+ .big_tomb_bits = self.liveness.special.get(inst) orelse 0,
+ .bit_index = 0,
+ };
+}
+
+fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
+ const ptr_bits = self.target.cpu.arch.ptrBitWidth();
+ const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+
+ // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
+ if (tv.ty.zigTypeTag() == .Pointer) blk: {
+ if (tv.ty.castPtrToFn()) |_| break :blk;
+ if (!tv.ty.elemType2().hasRuntimeBits()) {
+ return MCValue.none;
+ }
+ }
+
+ decl.alive = true;
+ if (self.bin_file.cast(link.File.Elf)) |elf_file| {
+ const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
+ const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else {
+ return self.fail("TODO codegen non-ELF const Decl pointer", .{});
+ }
+}
+
fn parseRegName(name: []const u8) ?Register {
if (@hasDecl(Register, "parseRegName")) {
return Register.parseRegName(name);
src/arch/sparcv9/Emit.zig
@@ -59,6 +59,11 @@ pub fn emitMir(
.jmpl => @panic("TODO implement sparcv9 jmpl"),
.jmpl_i => @panic("TODO implement sparcv9 jmpl to reg"),
+ .ldub => try emit.mirArithmetic3Op(inst),
+ .lduh => try emit.mirArithmetic3Op(inst),
+ .lduw => try emit.mirArithmetic3Op(inst),
+ .ldx => try emit.mirArithmetic3Op(inst),
+
.@"or" => try emit.mirArithmetic3Op(inst),
.nop => try emit.mirNop(),
@@ -68,7 +73,7 @@ pub fn emitMir(
.save => try emit.mirArithmetic3Op(inst),
.restore => try emit.mirArithmetic3Op(inst),
- .sethi => @panic("TODO implement sparcv9 sethi"),
+ .sethi => try emit.mirSethi(inst),
.sllx => @panic("TODO implement sparcv9 sllx"),
@@ -158,6 +163,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
const imm = data.rs2_or_imm.imm;
switch (tag) {
.add => try emit.writeInstruction(Instruction.add(i13, rs1, imm, rd)),
+ .ldub => try emit.writeInstruction(Instruction.ldub(i13, rs1, imm, rd)),
+ .lduh => try emit.writeInstruction(Instruction.lduh(i13, rs1, imm, rd)),
+ .lduw => try emit.writeInstruction(Instruction.lduw(i13, rs1, imm, rd)),
+ .ldx => try emit.writeInstruction(Instruction.ldx(i13, rs1, imm, rd)),
.@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)),
.save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)),
.restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)),
@@ -168,6 +177,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
const rs2 = data.rs2_or_imm.rs2;
switch (tag) {
.add => try emit.writeInstruction(Instruction.add(Register, rs1, rs2, rd)),
+ .ldub => try emit.writeInstruction(Instruction.ldub(Register, rs1, rs2, rd)),
+ .lduh => try emit.writeInstruction(Instruction.lduh(Register, rs1, rs2, rd)),
+ .lduw => try emit.writeInstruction(Instruction.lduw(Register, rs1, rs2, rd)),
+ .ldx => try emit.writeInstruction(Instruction.ldx(Register, rs1, rs2, rd)),
.@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)),
.save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)),
.restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)),
@@ -181,6 +194,17 @@ fn mirNop(emit: *Emit) !void {
try emit.writeInstruction(Instruction.nop());
}
+fn mirSethi(emit: *Emit, inst: Mir.Inst.Index) !void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
+ const data = emit.mir.instructions.items(.data)[inst].sethi;
+
+ const imm = data.imm;
+ const rd = data.rd;
+
+ assert(tag == .sethi);
+ try emit.writeInstruction(Instruction.sethi(imm, rd));
+}
+
fn mirTrap(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const data = emit.mir.instructions.items(.data)[inst].trap;
src/arch/sparcv9/Mir.zig
@@ -60,6 +60,16 @@ pub const Inst = struct {
jmpl,
jmpl_i,
+ /// A.27 Load Integer
+ /// Those uses the arithmetic_3op field.
+ /// Note that the ldd variant of this instruction is deprecated, do not emit
+ /// it unless specifically requested (e.g. by inline assembly).
+ // TODO add other operations.
+ ldub,
+ lduh,
+ lduw,
+ ldx,
+
/// A.31 Logical Operations
/// Those uses the arithmetic_3op field.
// TODO add other operations.