| ... | @@ -2,6 +2,7 @@ | ... | @@ -2,6 +2,7 @@ |
| 2 | //! machine code | 2 | //! machine code |
| 3 | | 3 | |
| 4 | const std = @import("std"); | 4 | const std = @import("std"); |
| | 5 | const Endian = std.builtin.Endian; |
| 5 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 6 | const link = @import("../../link.zig"); | 7 | const link = @import("../../link.zig"); |
| 7 | const Module = @import("../../Module.zig"); | 8 | const Module = @import("../../Module.zig"); |
| ... | @@ -14,6 +15,8 @@ const leb128 = std.leb; | ... | @@ -14,6 +15,8 @@ const leb128 = std.leb; |
| 14 | const Emit = @This(); | 15 | const Emit = @This(); |
| 15 | const Mir = @import("Mir.zig"); | 16 | const Mir = @import("Mir.zig"); |
| 16 | const bits = @import("bits.zig"); | 17 | const bits = @import("bits.zig"); |
| | 18 | const Instruction = bits.Instruction; |
| | 19 | const Register = bits.Register; |
| 17 | | 20 | |
| 18 | mir: Mir, | 21 | mir: Mir, |
| 19 | bin_file: *link.File, | 22 | bin_file: *link.File, |
| ... | @@ -47,7 +50,7 @@ pub fn emitMir( | ... | @@ -47,7 +50,7 @@ pub fn emitMir( |
| 47 | .dbg_prologue_end => try emit.mirDebugPrologueEnd(), | 50 | .dbg_prologue_end => try emit.mirDebugPrologueEnd(), |
| 48 | .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(), | 51 | .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(), |
| 49 | | 52 | |
| 50 | .add => @panic("TODO implement sparcv9 add"), | 53 | .add => try emit.mirArithmetic3Op(inst), |
| 51 | | 54 | |
| 52 | .bpcc => @panic("TODO implement sparcv9 bpcc"), | 55 | .bpcc => @panic("TODO implement sparcv9 bpcc"), |
| 53 | | 56 | |
| ... | @@ -56,22 +59,22 @@ pub fn emitMir( | ... | @@ -56,22 +59,22 @@ pub fn emitMir( |
| 56 | .jmpl => @panic("TODO implement sparcv9 jmpl"), | 59 | .jmpl => @panic("TODO implement sparcv9 jmpl"), |
| 57 | .jmpl_i => @panic("TODO implement sparcv9 jmpl to reg"), | 60 | .jmpl_i => @panic("TODO implement sparcv9 jmpl to reg"), |
| 58 | | 61 | |
| 59 | .@"or" => @panic("TODO implement sparcv9 or"), | 62 | .@"or" => try emit.mirArithmetic3Op(inst), |
| 60 | | 63 | |
| 61 | .nop => @panic("TODO implement sparcv9 nop"), | 64 | .nop => try emit.mirNop(), |
| 62 | | 65 | |
| 63 | .@"return" => @panic("TODO implement sparcv9 return"), | 66 | .@"return" => try emit.mirArithmetic2Op(inst), |
| 64 | | 67 | |
| 65 | .save => @panic("TODO implement sparcv9 save"), | 68 | .save => try emit.mirArithmetic3Op(inst), |
| 66 | .restore => @panic("TODO implement sparcv9 restore"), | 69 | .restore => try emit.mirArithmetic3Op(inst), |
| 67 | | 70 | |
| 68 | .sethi => @panic("TODO implement sparcv9 sethi"), | 71 | .sethi => @panic("TODO implement sparcv9 sethi"), |
| 69 | | 72 | |
| 70 | .sllx => @panic("TODO implement sparcv9 sllx"), | 73 | .sllx => @panic("TODO implement sparcv9 sllx"), |
| 71 | | 74 | |
| 72 | .sub => @panic("TODO implement sparcv9 sub"), | 75 | .sub => try emit.mirArithmetic3Op(inst), |
| 73 | | 76 | |
| 74 | .tcc => @panic("TODO implement sparcv9 tcc"), | 77 | .tcc => try emit.mirTrap(inst), |
| 75 | } | 78 | } |
| 76 | } | 79 | } |
| 77 | } | 80 | } |
| ... | @@ -80,6 +83,129 @@ pub fn deinit(emit: *Emit) void { | ... | @@ -80,6 +83,129 @@ pub fn deinit(emit: *Emit) void { |
| 80 | emit.* = undefined; | 83 | emit.* = undefined; |
| 81 | } | 84 | } |
| 82 | | 85 | |
| | 86 | fn mirDbgArg(emit: *Emit, inst: Mir.Inst.Index) !void { |
| | 87 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| | 88 | const dbg_arg_info = emit.mir.instructions.items(.data)[inst].dbg_arg_info; |
| | 89 | _ = dbg_arg_info; |
| | 90 | |
| | 91 | switch (tag) { |
| | 92 | .dbg_arg => {}, // TODO try emit.genArgDbgInfo(dbg_arg_info.air_inst, dbg_arg_info.arg_index), |
| | 93 | else => unreachable, |
| | 94 | } |
| | 95 | } |
| | 96 | |
| | 97 | fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { |
| | 98 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| | 99 | const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column; |
| | 100 | |
| | 101 | switch (tag) { |
| | 102 | .dbg_line => try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column), |
| | 103 | else => unreachable, |
| | 104 | } |
| | 105 | } |
| | 106 | |
| | 107 | fn mirDebugPrologueEnd(self: *Emit) !void { |
| | 108 | switch (self.debug_output) { |
| | 109 | .dwarf => |dbg_out| { |
| | 110 | try dbg_out.dbg_line.append(DW.LNS.set_prologue_end); |
| | 111 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| | 112 | }, |
| | 113 | .plan9 => {}, |
| | 114 | .none => {}, |
| | 115 | } |
| | 116 | } |
| | 117 | |
| | 118 | fn mirDebugEpilogueBegin(self: *Emit) !void { |
| | 119 | switch (self.debug_output) { |
| | 120 | .dwarf => |dbg_out| { |
| | 121 | try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin); |
| | 122 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); |
| | 123 | }, |
| | 124 | .plan9 => {}, |
| | 125 | .none => {}, |
| | 126 | } |
| | 127 | } |
| | 128 | |
| | 129 | fn mirArithmetic2Op(emit: *Emit, inst: Mir.Inst.Index) !void { |
| | 130 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| | 131 | const data = emit.mir.instructions.items(.data)[inst].arithmetic_2op; |
| | 132 | |
| | 133 | const rs1 = data.rs1; |
| | 134 | |
| | 135 | if (data.is_imm) { |
| | 136 | const imm = data.rs2_or_imm.imm; |
| | 137 | switch (tag) { |
| | 138 | .@"return" => try emit.writeInstruction(Instruction.@"return"(i13, rs1, imm)), |
| | 139 | else => unreachable, |
| | 140 | } |
| | 141 | } else { |
| | 142 | const rs2 = data.rs2_or_imm.rs2; |
| | 143 | switch (tag) { |
| | 144 | .@"return" => try emit.writeInstruction(Instruction.@"return"(Register, rs1, rs2)), |
| | 145 | else => unreachable, |
| | 146 | } |
| | 147 | } |
| | 148 | } |
| | 149 | |
| | 150 | fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { |
| | 151 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| | 152 | const data = emit.mir.instructions.items(.data)[inst].arithmetic_3op; |
| | 153 | |
| | 154 | const rd = data.rd; |
| | 155 | const rs1 = data.rs1; |
| | 156 | |
| | 157 | if (data.is_imm) { |
| | 158 | const imm = data.rs2_or_imm.imm; |
| | 159 | switch (tag) { |
| | 160 | .add => try emit.writeInstruction(Instruction.add(i13, rs1, imm, rd)), |
| | 161 | .@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)), |
| | 162 | .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)), |
| | 163 | .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)), |
| | 164 | .sub => try emit.writeInstruction(Instruction.sub(i13, rs1, imm, rd)), |
| | 165 | else => unreachable, |
| | 166 | } |
| | 167 | } else { |
| | 168 | const rs2 = data.rs2_or_imm.rs2; |
| | 169 | switch (tag) { |
| | 170 | .add => try emit.writeInstruction(Instruction.add(Register, rs1, rs2, rd)), |
| | 171 | .@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)), |
| | 172 | .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)), |
| | 173 | .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)), |
| | 174 | .sub => try emit.writeInstruction(Instruction.sub(Register, rs1, rs2, rd)), |
| | 175 | else => unreachable, |
| | 176 | } |
| | 177 | } |
| | 178 | } |
| | 179 | |
| | 180 | fn mirNop(emit: *Emit) !void { |
| | 181 | try emit.writeInstruction(Instruction.nop()); |
| | 182 | } |
| | 183 | |
| | 184 | fn mirTrap(emit: *Emit, inst: Mir.Inst.Index) !void { |
| | 185 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| | 186 | const data = emit.mir.instructions.items(.data)[inst].trap; |
| | 187 | |
| | 188 | const cond = data.cond; |
| | 189 | const ccr = data.ccr; |
| | 190 | const rs1 = data.rs1; |
| | 191 | |
| | 192 | if (data.is_imm) { |
| | 193 | const imm = data.rs2_or_imm.imm; |
| | 194 | switch (tag) { |
| | 195 | .tcc => try emit.writeInstruction(Instruction.trap(u7, cond, ccr, rs1, imm)), |
| | 196 | else => unreachable, |
| | 197 | } |
| | 198 | } else { |
| | 199 | const rs2 = data.rs2_or_imm.rs2; |
| | 200 | switch (tag) { |
| | 201 | .tcc => try emit.writeInstruction(Instruction.trap(Register, cond, ccr, rs1, rs2)), |
| | 202 | else => unreachable, |
| | 203 | } |
| | 204 | } |
| | 205 | } |
| | 206 | |
| | 207 | // Common helper functions |
| | 208 | |
| 83 | fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { | 209 | fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { |
| 84 | const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line); | 210 | const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line); |
| 85 | const delta_pc: usize = self.code.items.len - self.prev_di_pc; | 211 | const delta_pc: usize = self.code.items.len - self.prev_di_pc; |
| ... | @@ -131,52 +257,18 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { | ... | @@ -131,52 +257,18 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { |
| 131 | } | 257 | } |
| 132 | } | 258 | } |
| 133 | | 259 | |
| 134 | fn mirDbgArg(emit: *Emit, inst: Mir.Inst.Index) !void { | | |
| 135 | const tag = emit.mir.instructions.items(.tag)[inst]; | | |
| 136 | const dbg_arg_info = emit.mir.instructions.items(.data)[inst].dbg_arg_info; | | |
| 137 | _ = dbg_arg_info; | | |
| 138 | | | |
| 139 | switch (tag) { | | |
| 140 | .dbg_arg => {}, // TODO try emit.genArgDbgInfo(dbg_arg_info.air_inst, dbg_arg_info.arg_index), | | |
| 141 | else => unreachable, | | |
| 142 | } | | |
| 143 | } | | |
| 144 | | | |
| 145 | fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { | | |
| 146 | const tag = emit.mir.instructions.items(.tag)[inst]; | | |
| 147 | const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column; | | |
| 148 | | | |
| 149 | switch (tag) { | | |
| 150 | .dbg_line => try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column), | | |
| 151 | else => unreachable, | | |
| 152 | } | | |
| 153 | } | | |
| 154 | | | |
| 155 | fn mirDebugPrologueEnd(self: *Emit) !void { | | |
| 156 | switch (self.debug_output) { | | |
| 157 | .dwarf => |dbg_out| { | | |
| 158 | try dbg_out.dbg_line.append(DW.LNS.set_prologue_end); | | |
| 159 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); | | |
| 160 | }, | | |
| 161 | .plan9 => {}, | | |
| 162 | .none => {}, | | |
| 163 | } | | |
| 164 | } | | |
| 165 | | | |
| 166 | fn mirDebugEpilogueBegin(self: *Emit) !void { | | |
| 167 | switch (self.debug_output) { | | |
| 168 | .dwarf => |dbg_out| { | | |
| 169 | try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin); | | |
| 170 | try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); | | |
| 171 | }, | | |
| 172 | .plan9 => {}, | | |
| 173 | .none => {}, | | |
| 174 | } | | |
| 175 | } | | |
| 176 | | | |
| 177 | fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { | 260 | fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { |
| 178 | @setCold(true); | 261 | @setCold(true); |
| 179 | assert(emit.err_msg == null); | 262 | assert(emit.err_msg == null); |
| 180 | emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args); | 263 | emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args); |
| 181 | return error.EmitFail; | 264 | return error.EmitFail; |
| 182 | } | 265 | } |
| | 266 | |
| | 267 | fn writeInstruction(emit: *Emit, instruction: Instruction) !void { |
| | 268 | // SPARCv9 instructions are always arranged in BE regardless of the |
| | 269 | // endianness mode the CPU is running in. |
| | 270 | // This is to ease porting in case someone wants to do a LE SPARCv9 backend. |
| | 271 | const endian = Endian.Big; |
| | 272 | |
| | 273 | std.mem.writeInt(u32, try emit.code.addManyAsArray(4), instruction.toU32(), endian); |
| | 274 | } |