mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 05:20:34 +00:00
stage2: sparcv9: Implement enough instruction to compile simple exes
This commit is contained in:
parent
1f63afa7c9
commit
1467590e40
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user