| ... | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | //! machine code |
| 3 | 3 | |
| 4 | 4 | const std = @import("std"); |
| 5 | const Endian = std.builtin.Endian; |
| 5 | 6 | const assert = std.debug.assert; |
| 6 | 7 | const link = @import("../../link.zig"); |
| 7 | 8 | const Module = @import("../../Module.zig"); |
| ... | ... | @@ -14,6 +15,8 @@ const leb128 = std.leb; |
| 14 | 15 | const Emit = @This(); |
| 15 | 16 | const Mir = @import("Mir.zig"); |
| 16 | 17 | const bits = @import("bits.zig"); |
| 18 | const Instruction = bits.Instruction; |
| 19 | const Register = bits.Register; |
| 17 | 20 | |
| 18 | 21 | mir: Mir, |
| 19 | 22 | bin_file: *link.File, |
| ... | ... | @@ -47,7 +50,7 @@ pub fn emitMir( |
| 47 | 50 | .dbg_prologue_end => try emit.mirDebugPrologueEnd(), |
| 48 | 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 | 55 | .bpcc => @panic("TODO implement sparcv9 bpcc"), |
| 53 | 56 | |
| ... | ... | @@ -56,22 +59,22 @@ pub fn emitMir( |
| 56 | 59 | .jmpl => @panic("TODO implement sparcv9 jmpl"), |
| 57 | 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"), |
| 66 | | .restore => @panic("TODO implement sparcv9 restore"), |
| 68 | .save => try emit.mirArithmetic3Op(inst), |
| 69 | .restore => try emit.mirArithmetic3Op(inst), |
| 67 | 70 | |
| 68 | 71 | .sethi => @panic("TODO implement sparcv9 sethi"), |
| 69 | 72 | |
| 70 | 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 | 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 | 209 | fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { |
| 84 | 210 | const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line); |
| 85 | 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 | 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 | 260 | fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { |
| 178 | 261 | @setCold(true); |
| 179 | 262 | assert(emit.err_msg == null); |
| 180 | 263 | emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args); |
| 181 | 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 | } |