aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/sparcv9/CodeGen.zig102
-rw-r--r--src/arch/sparcv9/Emit.zig16
-rw-r--r--src/arch/sparcv9/Mir.zig47
3 files changed, 162 insertions, 3 deletions
diff --git a/src/arch/sparcv9/CodeGen.zig b/src/arch/sparcv9/CodeGen.zig
index 0c63d992ee..c2aa082b11 100644
--- a/src/arch/sparcv9/CodeGen.zig
+++ b/src/arch/sparcv9/CodeGen.zig
@@ -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 {
+ const cc = self.fn_type.fnCallingConvention();
+ if (cc != .Naked) {
+ // TODO Finish function prologue and epilogue for sparcv9.
+
+ // 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);
- @panic("TODO implement gen");
+ 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 {
diff --git a/src/arch/sparcv9/Emit.zig b/src/arch/sparcv9/Emit.zig
index 2587b94c7c..28c172f329 100644
--- a/src/arch/sparcv9/Emit.zig
+++ b/src/arch/sparcv9/Emit.zig
@@ -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;
+}
diff --git a/src/arch/sparcv9/Mir.zig b/src/arch/sparcv9/Mir.zig
index c8b9c6544f..43b008d189 100644
--- a/src/arch/sparcv9/Mir.zig
+++ b/src/arch/sparcv9/Mir.zig
@@ -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,
};
}
-