mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 21:38:33 +00:00
riscv: initial cleanup and work
This commit is contained in:
parent
1550b5b16d
commit
dceff2592f
@ -759,6 +759,13 @@ else
|
||||
pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr: ?usize) noreturn {
|
||||
@setCold(true);
|
||||
|
||||
// stage2_riscv64 backend doesn't support loops yet.
|
||||
if (builtin.zig_backend == .stage2_riscv64 or
|
||||
builtin.cpu.arch == .riscv64)
|
||||
{
|
||||
unreachable;
|
||||
}
|
||||
|
||||
// For backends that cannot handle the language features depended on by the
|
||||
// default panic handler, we have a simpler panic handler:
|
||||
if (builtin.zig_backend == .stage2_wasm or
|
||||
@ -766,7 +773,6 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
|
||||
builtin.zig_backend == .stage2_aarch64 or
|
||||
builtin.zig_backend == .stage2_x86 or
|
||||
(builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or
|
||||
builtin.zig_backend == .stage2_riscv64 or
|
||||
builtin.zig_backend == .stage2_sparc64 or
|
||||
builtin.zig_backend == .stage2_spirv64)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -27,6 +27,8 @@ prev_di_column: u32,
|
||||
/// Relative to the beginning of `code`.
|
||||
prev_di_pc: usize,
|
||||
|
||||
const log = std.log.scoped(.emit);
|
||||
|
||||
const InnerError = error{
|
||||
OutOfMemory,
|
||||
EmitFail,
|
||||
@ -37,33 +39,57 @@ pub fn emitMir(
|
||||
) InnerError!void {
|
||||
const mir_tags = emit.mir.instructions.items(.tag);
|
||||
|
||||
// TODO: compute branch offsets
|
||||
// try emit.lowerMir();
|
||||
|
||||
// Emit machine code
|
||||
for (mir_tags, 0..) |tag, index| {
|
||||
const inst = @as(u32, @intCast(index));
|
||||
log.debug("emitMir: {s}", .{@tagName(tag)});
|
||||
switch (tag) {
|
||||
.add => try emit.mirRType(inst),
|
||||
.sub => try emit.mirRType(inst),
|
||||
|
||||
.cmp_eq => try emit.mirRType(inst),
|
||||
.cmp_gt => try emit.mirRType(inst),
|
||||
|
||||
.beq => try emit.mirBType(inst),
|
||||
.bne => try emit.mirBType(inst),
|
||||
|
||||
.addi => try emit.mirIType(inst),
|
||||
.jalr => try emit.mirIType(inst),
|
||||
.ld => try emit.mirIType(inst),
|
||||
.sd => try emit.mirIType(inst),
|
||||
|
||||
.jal => try emit.mirJType(inst),
|
||||
|
||||
.ebreak => try emit.mirSystem(inst),
|
||||
.ecall => try emit.mirSystem(inst),
|
||||
.unimp => try emit.mirSystem(inst),
|
||||
|
||||
.dbg_line => try emit.mirDbgLine(inst),
|
||||
|
||||
.dbg_prologue_end => try emit.mirDebugPrologueEnd(),
|
||||
.dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
|
||||
|
||||
.psuedo_prologue => try emit.mirPsuedo(inst),
|
||||
.psuedo_jump => try emit.mirPsuedo(inst),
|
||||
|
||||
.mv => try emit.mirRR(inst),
|
||||
|
||||
.nop => try emit.mirNop(inst),
|
||||
.ret => try emit.mirNop(inst),
|
||||
|
||||
.lui => try emit.mirUType(inst),
|
||||
|
||||
.ld => try emit.mirIType(inst),
|
||||
.sd => try emit.mirIType(inst),
|
||||
.lw => try emit.mirIType(inst),
|
||||
.sw => try emit.mirIType(inst),
|
||||
.lh => try emit.mirIType(inst),
|
||||
.sh => try emit.mirIType(inst),
|
||||
.lb => try emit.mirIType(inst),
|
||||
.sb => try emit.mirIType(inst),
|
||||
.ldr_ptr_stack => try emit.mirIType(inst),
|
||||
|
||||
.load_symbol => try emit.mirLoadSymbol(inst),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -86,15 +112,19 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
|
||||
return error.EmitFail;
|
||||
}
|
||||
|
||||
fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
|
||||
const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(self.prev_di_line));
|
||||
const delta_pc: usize = self.code.items.len - self.prev_di_pc;
|
||||
switch (self.debug_output) {
|
||||
fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {
|
||||
log.debug("Line: {} {}\n", .{ line, emit.prev_di_line });
|
||||
const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));
|
||||
const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
|
||||
log.debug("(advance pc={d} and line={d})", .{ delta_pc, delta_line });
|
||||
switch (emit.debug_output) {
|
||||
.dwarf => |dw| {
|
||||
if (column != emit.prev_di_column) try dw.setColumn(column);
|
||||
if (delta_line == 0) return; // TODO: remove this
|
||||
try dw.advancePCAndLine(delta_line, delta_pc);
|
||||
self.prev_di_line = line;
|
||||
self.prev_di_column = column;
|
||||
self.prev_di_pc = self.code.items.len;
|
||||
emit.prev_di_line = line;
|
||||
emit.prev_di_column = column;
|
||||
emit.prev_di_pc = emit.code.items.len;
|
||||
},
|
||||
.plan9 => |dbg_out| {
|
||||
if (delta_pc <= 0) return; // only do this when the pc changes
|
||||
@ -113,12 +143,12 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
|
||||
// we don't need to do anything, because adding the pc quanta does it for us
|
||||
} else unreachable;
|
||||
if (dbg_out.start_line == null)
|
||||
dbg_out.start_line = self.prev_di_line;
|
||||
dbg_out.start_line = emit.prev_di_line;
|
||||
dbg_out.end_line = line;
|
||||
// only do this if the pc changed
|
||||
self.prev_di_line = line;
|
||||
self.prev_di_column = column;
|
||||
self.prev_di_pc = self.code.items.len;
|
||||
emit.prev_di_line = line;
|
||||
emit.prev_di_column = column;
|
||||
emit.prev_di_pc = emit.code.items.len;
|
||||
},
|
||||
.none => {},
|
||||
}
|
||||
@ -131,6 +161,19 @@ fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
switch (tag) {
|
||||
.add => try emit.writeInstruction(Instruction.add(r_type.rd, r_type.rs1, r_type.rs2)),
|
||||
.sub => try emit.writeInstruction(Instruction.sub(r_type.rd, r_type.rs1, r_type.rs2)),
|
||||
.cmp_eq => try emit.writeInstruction(Instruction.slt(r_type.rd, r_type.rs1, r_type.rs2)),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn mirBType(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const b_type = emit.mir.instructions.items(.data)[inst].b_type;
|
||||
|
||||
// const inst = b_type.imm12;
|
||||
|
||||
switch (tag) {
|
||||
.beq => try emit.writeInstruction(Instruction.beq(b_type.rs1, b_type.rs2, b_type.imm12)),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
@ -142,8 +185,30 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
switch (tag) {
|
||||
.addi => try emit.writeInstruction(Instruction.addi(i_type.rd, i_type.rs1, i_type.imm12)),
|
||||
.jalr => try emit.writeInstruction(Instruction.jalr(i_type.rd, i_type.imm12, i_type.rs1)),
|
||||
|
||||
.ld => try emit.writeInstruction(Instruction.ld(i_type.rd, i_type.imm12, i_type.rs1)),
|
||||
.sd => try emit.writeInstruction(Instruction.sd(i_type.rd, i_type.imm12, i_type.rs1)),
|
||||
.lw => try emit.writeInstruction(Instruction.lw(i_type.rd, i_type.imm12, i_type.rs1)),
|
||||
.sw => try emit.writeInstruction(Instruction.sw(i_type.rd, i_type.imm12, i_type.rs1)),
|
||||
.lh => try emit.writeInstruction(Instruction.lh(i_type.rd, i_type.imm12, i_type.rs1)),
|
||||
.sh => try emit.writeInstruction(Instruction.sh(i_type.rd, i_type.imm12, i_type.rs1)),
|
||||
.lb => try emit.writeInstruction(Instruction.lb(i_type.rd, i_type.imm12, i_type.rs1)),
|
||||
.sb => try emit.writeInstruction(Instruction.sb(i_type.rd, i_type.imm12, i_type.rs1)),
|
||||
|
||||
.ldr_ptr_stack => try emit.writeInstruction(Instruction.add(i_type.rd, i_type.rs1, .sp)),
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn mirJType(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const j_type = emit.mir.instructions.items(.data)[inst].j_type;
|
||||
|
||||
switch (tag) {
|
||||
.jal => {
|
||||
try emit.writeInstruction(Instruction.jal(j_type.rd, j_type.imm21));
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
@ -169,28 +234,55 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn mirDebugPrologueEnd(self: *Emit) !void {
|
||||
switch (self.debug_output) {
|
||||
fn mirDebugPrologueEnd(emit: *Emit) !void {
|
||||
switch (emit.debug_output) {
|
||||
.dwarf => |dw| {
|
||||
try dw.setPrologueEnd();
|
||||
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
|
||||
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
|
||||
},
|
||||
.plan9 => {},
|
||||
.none => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn mirDebugEpilogueBegin(self: *Emit) !void {
|
||||
switch (self.debug_output) {
|
||||
fn mirDebugEpilogueBegin(emit: *Emit) !void {
|
||||
switch (emit.debug_output) {
|
||||
.dwarf => |dw| {
|
||||
try dw.setEpilogueBegin();
|
||||
try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
|
||||
try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
|
||||
},
|
||||
.plan9 => {},
|
||||
.none => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn mirPsuedo(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const data = emit.mir.instructions.items(.data)[inst];
|
||||
|
||||
switch (tag) {
|
||||
.psuedo_prologue => {
|
||||
const imm12 = data.imm12;
|
||||
const stack_size: i12 = @max(32, imm12);
|
||||
|
||||
try emit.writeInstruction(Instruction.addi(.sp, .sp, -stack_size));
|
||||
try emit.writeInstruction(Instruction.sd(.ra, stack_size - 8, .sp));
|
||||
try emit.writeInstruction(Instruction.sd(.s0, stack_size - 16, .sp));
|
||||
try emit.writeInstruction(Instruction.addi(.s0, .sp, stack_size));
|
||||
},
|
||||
|
||||
.psuedo_jump => {
|
||||
const target = data.inst;
|
||||
const offset: i12 = @intCast(emit.code.items.len);
|
||||
_ = target;
|
||||
|
||||
try emit.writeInstruction(Instruction.jal(.s0, offset));
|
||||
},
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn mirRR(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const rr = emit.mir.instructions.items(.data)[inst].rr;
|
||||
@ -200,6 +292,7 @@ fn mirRR(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn mirUType(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const u_type = emit.mir.instructions.items(.data)[inst].u_type;
|
||||
@ -219,3 +312,63 @@ fn mirNop(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn mirLoadSymbol(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
// const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
const payload = emit.mir.instructions.items(.data)[inst].payload;
|
||||
const data = emit.mir.extraData(Mir.LoadSymbolPayload, payload).data;
|
||||
const reg = @as(Register, @enumFromInt(data.register));
|
||||
|
||||
const end_offset = @as(u32, @intCast(emit.code.items.len));
|
||||
try emit.writeInstruction(Instruction.lui(reg, 0));
|
||||
try emit.writeInstruction(Instruction.lw(reg, 0, reg));
|
||||
|
||||
switch (emit.bin_file.tag) {
|
||||
.elf => {
|
||||
const elf_file = emit.bin_file.cast(link.File.Elf).?;
|
||||
const atom_ptr = elf_file.symbol(data.atom_index).atom(elf_file).?;
|
||||
|
||||
const hi_r_type = @intFromEnum(std.elf.R_RISCV.HI20);
|
||||
|
||||
try atom_ptr.addReloc(elf_file, .{
|
||||
.r_offset = end_offset,
|
||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | hi_r_type,
|
||||
.r_addend = 0,
|
||||
});
|
||||
|
||||
const lo_r_type = @intFromEnum(std.elf.R_RISCV.LO12_I);
|
||||
|
||||
try atom_ptr.addReloc(elf_file, .{
|
||||
.r_offset = end_offset + 4,
|
||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | lo_r_type,
|
||||
.r_addend = 0,
|
||||
});
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn isBranch(tag: Mir.Inst.Tag) bool {
|
||||
switch (tag) {
|
||||
.psuedo_jump => true,
|
||||
else => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn lowerMir(emit: *Emit) !void {
|
||||
const comp = emit.bin_file.comp;
|
||||
const gpa = comp.gpa;
|
||||
const mir_tags = emit.mir.instructions.items(.tag);
|
||||
|
||||
_ = gpa;
|
||||
|
||||
for (mir_tags, 0..) |tag, index| {
|
||||
const inst: u32 = @intCast(index);
|
||||
|
||||
if (isBranch(tag)) {
|
||||
const target_inst = emit.mir.instructions.items(.data)[inst].inst;
|
||||
|
||||
_ = target_inst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,25 +24,72 @@ pub const Inst = struct {
|
||||
data: Data,
|
||||
|
||||
pub const Tag = enum(u16) {
|
||||
add,
|
||||
addi,
|
||||
jalr,
|
||||
lui,
|
||||
mv,
|
||||
|
||||
unimp,
|
||||
ebreak,
|
||||
ecall,
|
||||
|
||||
/// Addition
|
||||
add,
|
||||
/// Subtraction
|
||||
sub,
|
||||
|
||||
jal,
|
||||
|
||||
// TODO: Maybe create a special data for compares that includes the ops
|
||||
/// Compare equal, uses r_type
|
||||
cmp_eq,
|
||||
/// Compare greater than, uses r_type
|
||||
cmp_gt,
|
||||
|
||||
/// Branch if equal Uses b_type
|
||||
beq,
|
||||
/// Branch if not eql Uses b_type
|
||||
bne,
|
||||
|
||||
nop,
|
||||
ret,
|
||||
|
||||
/// Load double (64 bits)
|
||||
ld,
|
||||
/// Store double (64 bits)
|
||||
sd,
|
||||
/// Load word (32 bits)
|
||||
lw,
|
||||
/// Store word (32 bits)
|
||||
sw,
|
||||
/// Load half (16 bits)
|
||||
lh,
|
||||
/// Store half (16 bits)
|
||||
sh,
|
||||
/// Load byte (8 bits)
|
||||
lb,
|
||||
/// Store byte (8 bits)
|
||||
sb,
|
||||
|
||||
/// Pseudo-instruction: End of prologue
|
||||
dbg_prologue_end,
|
||||
/// Pseudo-instruction: Beginning of epilogue
|
||||
dbg_epilogue_begin,
|
||||
/// Pseudo-instruction: Update debug line
|
||||
dbg_line,
|
||||
unimp,
|
||||
ebreak,
|
||||
ecall,
|
||||
jalr,
|
||||
ld,
|
||||
lui,
|
||||
mv,
|
||||
nop,
|
||||
ret,
|
||||
sd,
|
||||
sub,
|
||||
|
||||
/// Psuedo-instruction that will generate a backpatched
|
||||
/// function prologue.
|
||||
psuedo_prologue,
|
||||
/// Jumps. Uses `inst` payload.
|
||||
psuedo_jump,
|
||||
|
||||
// TODO: add description
|
||||
load_symbol,
|
||||
|
||||
// TODO: add description
|
||||
// this is bad, remove this
|
||||
ldr_ptr_stack,
|
||||
};
|
||||
|
||||
/// The position of an MIR instruction within the `Mir` instructions array.
|
||||
@ -63,7 +110,11 @@ pub const Inst = struct {
|
||||
/// A 16-bit immediate value.
|
||||
///
|
||||
/// Used by e.g. svc
|
||||
imm16: u16,
|
||||
imm16: i16,
|
||||
/// A 12-bit immediate value.
|
||||
///
|
||||
/// Used by e.g. psuedo_prologue
|
||||
imm12: i12,
|
||||
/// Index into `extra`. Meaning of what can be found there is context-dependent.
|
||||
///
|
||||
/// Used by e.g. load_memory
|
||||
@ -95,6 +146,21 @@ pub const Inst = struct {
|
||||
rs1: Register,
|
||||
rs2: Register,
|
||||
},
|
||||
/// B-Type
|
||||
///
|
||||
/// Used by e.g. beq
|
||||
b_type: struct {
|
||||
rs1: Register,
|
||||
rs2: Register,
|
||||
imm12: i13,
|
||||
},
|
||||
/// J-Type
|
||||
///
|
||||
/// Used by e.g. jal
|
||||
j_type: struct {
|
||||
rd: Register,
|
||||
imm21: i21,
|
||||
},
|
||||
/// U-Type
|
||||
///
|
||||
/// Used by e.g. lui
|
||||
@ -111,10 +177,19 @@ pub const Inst = struct {
|
||||
},
|
||||
};
|
||||
|
||||
const CompareOp = enum {
|
||||
eq,
|
||||
neq,
|
||||
gt,
|
||||
gte,
|
||||
lt,
|
||||
lte,
|
||||
};
|
||||
|
||||
// Make sure we don't accidentally make instructions bigger than expected.
|
||||
// Note that in safety builds, Zig is allowed to insert a secret field for safety checks.
|
||||
// Note that in Debug builds, Zig is allowed to insert a secret field for safety checks.
|
||||
// comptime {
|
||||
// if (!std.debug.runtime_safety) {
|
||||
// if (builtin.mode != .Debug) {
|
||||
// assert(@sizeOf(Inst) == 8);
|
||||
// }
|
||||
// }
|
||||
@ -145,3 +220,9 @@ pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end
|
||||
.end = i,
|
||||
};
|
||||
}
|
||||
|
||||
pub const LoadSymbolPayload = struct {
|
||||
register: u32,
|
||||
atom_index: u32,
|
||||
sym_index: u32,
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user