stage2: sparcv9: Implement basic prologue/epilogue Mir emission

This commit is contained in:
Koakuma 2022-04-01 19:28:24 +07:00
parent 927706e6d0
commit 94a84e783e
3 changed files with 163 additions and 4 deletions

View File

@ -382,9 +382,109 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, is_caller: bool) !Ca
/// Caller must call `CallMCValues.deinit`.
fn gen(self: *Self) !void {
_ = self;
const cc = self.fn_type.fnCallingConvention();
if (cc != .Naked) {
// TODO Finish function prologue and epilogue for sparcv9.
@panic("TODO implement gen");
// TODO Backpatch stack offset
// save %sp, -176, %sp
_ = try self.addInst(.{
.tag = .save,
.data = .{
.arithmetic_3op = .{
.is_imm = true,
.rd = .sp,
.rs1 = .sp,
.rs2_or_imm = .{ .imm = -176 },
},
},
});
_ = try self.addInst(.{
.tag = .dbg_prologue_end,
.data = .{ .nop = {} },
});
try self.genBody(self.air.getMainBody());
_ = try self.addInst(.{
.tag = .dbg_epilogue_begin,
.data = .{ .nop = {} },
});
// exitlude jumps
if (self.exitlude_jump_relocs.items.len > 0 and
self.exitlude_jump_relocs.items[self.exitlude_jump_relocs.items.len - 1] == self.mir_instructions.len - 2)
{
// If the last Mir instruction (apart from the
// dbg_epilogue_begin) is the last exitlude jump
// relocation (which would just jump one instruction
// further), it can be safely removed
self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.pop());
}
for (self.exitlude_jump_relocs.items) |jmp_reloc| {
_ = jmp_reloc;
return self.fail("TODO add branches in sparcv9", .{});
}
// return %i7 + 8
_ = try self.addInst(.{
.tag = .@"return",
.data = .{
.arithmetic_2op = .{
.is_imm = true,
.rs1 = .@"i7",
.rs2_or_imm = .{ .imm = 8 },
},
},
});
// TODO Find a way to fill this slot
// nop
_ = try self.addInst(.{
.tag = .nop,
.data = .{ .nop = {} },
});
} else {
_ = try self.addInst(.{
.tag = .dbg_prologue_end,
.data = .{ .nop = {} },
});
try self.genBody(self.air.getMainBody());
_ = try self.addInst(.{
.tag = .dbg_epilogue_begin,
.data = .{ .nop = {} },
});
}
// Drop them off at the rbrace.
_ = try self.addInst(.{
.tag = .dbg_line,
.data = .{ .dbg_line_column = .{
.line = self.end_di_line,
.column = self.end_di_column,
} },
});
}
fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
_ = self;
_ = body;
@panic("TODO implement genBody");
}
fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
const gpa = self.gpa;
try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
const result_index = @intCast(Air.Inst.Index, self.mir_instructions.len);
self.mir_instructions.appendAssumeCapacity(inst);
return result_index;
}
fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError {

View File

@ -2,6 +2,7 @@
//! machine code
const std = @import("std");
const assert = std.debug.assert;
const link = @import("../../link.zig");
const Module = @import("../../Module.zig");
const ErrorMsg = Module.ErrorMsg;
@ -41,9 +42,15 @@ pub fn emitMir(
const inst = @intCast(u32, index);
switch (tag) {
.dbg_line => try emit.mirDbgLine(inst),
.dbg_prologue_end => try emit.mirDebugPrologueEnd(),
.dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
.nop => @panic("TODO implement nop"),
.save => @panic("TODO implement save"),
.restore => @panic("TODO implement restore"),
.@"return" => @panic("TODO implement return"),
}
}
}
@ -91,3 +98,10 @@ fn mirDebugEpilogueBegin(self: *Emit) !void {
.none => {},
}
}
fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
@setCold(true);
assert(emit.err_msg == null);
emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args);
return error.EmitFail;
}

View File

@ -29,6 +29,22 @@ pub const Inst = struct {
dbg_epilogue_begin,
/// Pseudo-instruction: Update debug line
dbg_line,
// All the real instructions are ordered by their section number
// in The SPARC Architecture Manual, Version 9.
/// A.40 No Operation
/// It uses the nop field.
nop,
/// A.46 SAVE and RESTORE
/// Those uses the arithmetic_3op field.
save,
restore,
/// A.45 RETURN
/// It uses the arithmetic_2op field.
@"return",
};
/// The position of an MIR instruction within the `Mir` instructions array.
@ -42,6 +58,36 @@ pub const Inst = struct {
///
/// Used by e.g. flushw
nop: void,
/// Three operand arithmetic.
/// if is_imm true then it uses the imm field of rs2_or_imm,
/// otherwise it uses rs2 field.
///
/// Used by e.g. add, sub
arithmetic_3op: struct {
is_imm: bool,
rd: Register,
rs1: Register,
rs2_or_imm: union {
rs2: Register,
imm: i13,
},
},
/// Two operand arithmetic.
/// if is_imm true then it uses the imm field of rs2_or_imm,
/// otherwise it uses rs2 field.
///
/// Used by e.g. return
arithmetic_2op: struct {
is_imm: bool,
rs1: Register,
rs2_or_imm: union {
rs2: Register,
imm: i13,
},
},
/// Debug info: line and column
///
/// Used by e.g. dbg_line
@ -77,4 +123,3 @@ pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end
.end = i,
};
}