From 94a84e783e32169268809e4aa4bdbfdff92d81e9 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Fri, 1 Apr 2022 19:28:24 +0700 Subject: [PATCH] stage2: sparcv9: Implement basic prologue/epilogue Mir emission --- src/arch/sparcv9/CodeGen.zig | 104 ++++++++++++++++++++++++++++++++++- src/arch/sparcv9/Emit.zig | 16 +++++- src/arch/sparcv9/Mir.zig | 47 +++++++++++++++- 3 files changed, 163 insertions(+), 4 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 { - _ = 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 { 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, }; } -