Skip to content

Commit

Permalink
riscv: first sign of floats!
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexicon226 committed Jun 13, 2024
1 parent 7ed2f21 commit 031d824
Show file tree
Hide file tree
Showing 11 changed files with 736 additions and 481 deletions.
559 changes: 285 additions & 274 deletions src/arch/riscv64/CodeGen.zig

Large diffs are not rendered by default.

355 changes: 259 additions & 96 deletions src/arch/riscv64/Encoding.zig

Large diffs are not rendered by default.

60 changes: 45 additions & 15 deletions src/arch/riscv64/Lower.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ result_relocs_len: u8 = undefined,
result_insts: [
@max(
1, // non-pseudo instruction
abi.callee_preserved_regs.len, // spill / restore regs,
abi.Registers.all_preserved.len, // spill / restore regs,
)
]Instruction = undefined,
result_relocs: [1]Reloc = undefined,
Expand Down Expand Up @@ -71,11 +71,24 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {

switch (inst.ops) {
.pseudo_load_rm => {
const tag: Encoding.Mnemonic = switch (rm.m.mod.size()) {
.byte => .lb,
.hword => .lh,
.word => .lw,
.dword => .ld,
const dest_reg = rm.r;
const dest_reg_class = dest_reg.class();
const float = dest_reg_class == .float;

const src_size = rm.m.mod.size();

const tag: Encoding.Mnemonic = if (!float)
switch (src_size) {
.byte => .lb,
.hword => .lh,
.word => .lw,
.dword => .ld,
}
else switch (src_size) {
.byte => unreachable, // Zig does not support 8-bit floats
.hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
.word => .flw,
.dword => .fld,
};

try lower.emit(tag, &.{
Expand All @@ -85,11 +98,25 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
});
},
.pseudo_store_rm => {
const tag: Encoding.Mnemonic = switch (rm.m.mod.size()) {
.byte => .sb,
.hword => .sh,
.word => .sw,
.dword => .sd,
const src_reg = rm.r;
const src_reg_class = src_reg.class();
const float = src_reg_class == .float;

// TODO: do we actually need this? are all stores not usize?
const dest_size = rm.m.mod.size();

const tag: Encoding.Mnemonic = if (!float)
switch (dest_size) {
.byte => .sb,
.hword => .sh,
.word => .sw,
.dword => .sd,
}
else switch (dest_size) {
.byte => unreachable, // Zig does not support 8-bit floats
.hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
.word => .fsw,
.dword => .fsd,
};

try lower.emit(tag, &.{
Expand Down Expand Up @@ -336,16 +363,19 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register
var reg_i: u31 = 0;
while (it.next()) |i| {
const frame = lower.mir.frame_locs.get(@intFromEnum(bits.FrameIndex.spill_frame));
const reg = abi.Registers.all_preserved[i];
const reg_class = reg.class();
const is_float_reg = reg_class == .float;

if (spilling) {
try lower.emit(.sd, &.{
try lower.emit(if (is_float_reg) .fsd else .sd, &.{
.{ .reg = frame.base },
.{ .reg = abi.callee_preserved_regs[i] },
.{ .reg = abi.Registers.all_preserved[i] },
.{ .imm = Immediate.s(frame.disp + reg_i) },
});
} else {
try lower.emit(.ld, &.{
.{ .reg = abi.callee_preserved_regs[i] },
try lower.emit(if (is_float_reg) .fld else .ld, &.{
.{ .reg = abi.Registers.all_preserved[i] },
.{ .reg = frame.base },
.{ .imm = Immediate.s(frame.disp + reg_i) },
});
Expand Down
59 changes: 20 additions & 39 deletions src/arch/riscv64/Mir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -20,87 +20,68 @@ pub const Inst = struct {
pub const Index = u32;

pub const Tag = enum(u16) {
/// Add immediate. Uses i_type payload.
addi,

/// Add immediate and produce a sign-extended result.
///
/// Uses i-type payload.
// base extension
addi,
addiw,

jalr,
lui,
mv,

@"and",
andi,

xor,
@"or",

ebreak,
ecall,
unimp,

/// OR instruction. Uses r_type payload.
@"or",

/// Addition
add,
/// Subtraction
sub,
/// Multiply, uses r_type. Needs the M extension.
mul,

/// Absolute Value, uses i_type payload.
abs,

sltu,
slt,

/// Immediate Logical Right Shift, uses i_type payload
srli,
/// Immediate Logical Left Shift, uses i_type payload
slli,
/// Immediate Arithmetic Right Shift, uses i_type payload.
srai,
/// Register Logical Left Shift, uses r_type payload
sllw,
/// Register Logical Right Shit, uses r_type payload
srlw,

/// Jumps, but stores the address of the instruction following the
/// jump in `rd`.
///
/// Uses j_type payload.
jal,

/// Immediate AND, uses i_type payload
andi,

/// Branch if equal, Uses b_type
beq,
/// Branch if not equal, Uses b_type
bne,

/// Generates a NO-OP, uses nop payload
nop,

/// Load double (64 bits), uses i_type payload
ld,
/// Load word (32 bits), uses i_type payload
lw,
/// Load half (16 bits), uses i_type payload
lh,
/// Load byte (8 bits), uses i_type payload
lb,

/// Store double (64 bits), uses s_type payload
sd,
/// Store word (32 bits), uses s_type payload
sw,
/// Store half (16 bits), uses s_type payload
sh,
/// Store byte (8 bits), uses s_type payload
sb,

// M extension
mul,

// F extension (32-bit float)
fadds,
flw,
fsw,
feqs,

// D extension (64-bit float)
faddd,
fld,
fsd,
feqd,

/// A pseudo-instruction. Used for anything that isn't 1:1 with an
/// assembly instruction.
pseudo,
Expand Down
113 changes: 66 additions & 47 deletions src/arch/riscv64/abi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -238,62 +238,81 @@ fn classifyStruct(
}
}

pub const callee_preserved_regs = [_]Register{
// .s0 is ommited to be used as a frame pointer
.s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
};
const allocatable_registers = Registers.Integer.all_regs ++ Registers.Float.all_regs;
pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);

pub const function_arg_regs = [_]Register{
.a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7,
};
// Register classes
const RegisterBitSet = RegisterManager.RegisterBitSet;

pub const function_ret_regs = [_]Register{
.a0, .a1,
pub const RegisterClass = enum {
int,
float,
};

pub const temporary_regs = [_]Register{
.t0, .t1, .t2, .t3, .t4, .t5, .t6,
};
pub const Registers = struct {
pub const all_preserved = Integer.callee_preserved_regs ++ Float.callee_preserved_regs;

const allocatable_registers = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
pub const Integer = struct {
// zig fmt: off
pub const general_purpose = initRegBitSet(0, callee_preserved_regs.len);
pub const function_arg = initRegBitSet(callee_preserved_regs.len, function_arg_regs.len);
pub const function_ret = initRegBitSet(callee_preserved_regs.len, function_ret_regs.len);
pub const temporary = initRegBitSet(callee_preserved_regs.len + function_arg_regs.len, temporary_regs.len);
// zig fmt: on

// Register classes
const RegisterBitSet = RegisterManager.RegisterBitSet;
pub const RegisterClass = struct {
pub const gp: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
set.setRangeValue(.{
.start = 0,
.end = callee_preserved_regs.len,
}, true);
break :blk set;
};
pub const callee_preserved_regs = [_]Register{
// .s0 is omitted to be used as the frame pointer register
.s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
};

pub const fa: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
set.setRangeValue(.{
.start = callee_preserved_regs.len,
.end = callee_preserved_regs.len + function_arg_regs.len,
}, true);
break :blk set;
};
pub const function_arg_regs = [_]Register{
.a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7,
};

pub const function_ret_regs = [_]Register{
.a0, .a1,
};

pub const temporary_regs = [_]Register{
.t0, .t1, .t2, .t3, .t4, .t5, .t6,
};

pub const fr: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
set.setRangeValue(.{
.start = callee_preserved_regs.len,
.end = callee_preserved_regs.len + function_ret_regs.len,
}, true);
break :blk set;
pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
};

pub const tp: RegisterBitSet = blk: {
var set = RegisterBitSet.initEmpty();
set.setRangeValue(.{
.start = callee_preserved_regs.len + function_arg_regs.len,
.end = callee_preserved_regs.len + function_arg_regs.len + temporary_regs.len,
}, true);
break :blk set;
pub const Float = struct {
// zig fmt: off
pub const general_purpose = initRegBitSet(Integer.all_regs.len, callee_preserved_regs.len);
pub const function_arg = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len, function_arg_regs.len);
pub const function_ret = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len, function_ret_regs.len);
pub const temporary = initRegBitSet(Integer.all_regs.len + callee_preserved_regs.len + function_arg_regs.len, temporary_regs.len);
// zig fmt: on

pub const callee_preserved_regs = [_]Register{
.fs0, .fs1, .fs2, .fs3, .fs4, .fs5, .fs6, .fs7, .fs8, .fs9, .fs10, .fs11,
};

pub const function_arg_regs = [_]Register{
.fa0, .fa1, .fa2, .fa3, .fa4, .fa5, .fa6, .fa7,
};

pub const function_ret_regs = [_]Register{
.fa0, .fa1,
};

pub const temporary_regs = [_]Register{
.ft0, .ft1, .ft2, .ft3, .ft4, .ft5, .ft6, .ft7, .ft8, .ft9, .ft10, .ft11,
};

pub const all_regs = callee_preserved_regs ++ function_arg_regs ++ temporary_regs;
};
};

fn initRegBitSet(start: usize, length: usize) RegisterBitSet {
var set = RegisterBitSet.initEmpty();
set.setRangeValue(.{
.start = start,
.end = start + length,
}, true);
return set;
}
Loading

0 comments on commit 031d824

Please sign in to comment.