Commit b2cb090c37
Changed files (6)
src
arch
codegen
src/arch/riscv64/abi.zig
@@ -7,7 +7,7 @@ const InternPool = @import("../../InternPool.zig");
const Module = @import("../../Module.zig");
const assert = std.debug.assert;
-pub const Class = enum { memory, byval, integer, double_integer, fields, none };
+pub const Class = enum { memory, byval, integer, double_integer, fields };
pub fn classifyType(ty: Type, mod: *Module) Class {
const target = mod.getTarget();
@@ -93,11 +93,13 @@ pub fn classifyType(ty: Type, mod: *Module) Class {
}
}
+pub const SystemClass = enum { integer, float, memory, none };
+
/// There are a maximum of 8 possible return slots. Returned values are in
/// the beginning of the array; unused slots are filled with .none.
-pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
- var result = [1]Class{.none} ** 8;
- const memory_class = [_]Class{
+pub fn classifySystem(ty: Type, zcu: *Module) [8]SystemClass {
+ var result = [1]SystemClass{.none} ** 8;
+ const memory_class = [_]SystemClass{
.memory, .none, .none, .none,
.none, .none, .none, .none,
};
@@ -139,6 +141,18 @@ pub fn classifySystem(ty: Type, zcu: *Module) [8]Class {
}
unreachable; // support > 128 bit int arguments
},
+ .Float => {
+ const target = zcu.getTarget();
+ const features = target.cpu.features;
+
+ const float_bits = ty.floatBits(zcu.getTarget());
+ const float_reg_size: u32 = if (std.Target.riscv.featureSetHas(features, .d)) 64 else 32;
+ if (float_bits <= float_reg_size) {
+ result[0] = .float;
+ return result;
+ }
+ unreachable; // support split float args
+ },
.ErrorUnion => {
const payload_ty = ty.errorUnionPayload(zcu);
const payload_bits = payload_ty.bitSize(zcu);
src/arch/riscv64/bits.zig
@@ -2,6 +2,9 @@ const std = @import("std");
const DW = std.dwarf;
const assert = std.debug.assert;
const testing = std.testing;
+const Target = std.Target;
+
+const Module = @import("../../Module.zig");
const Encoding = @import("Encoding.zig");
const Mir = @import("Mir.zig");
const abi = @import("abi.zig");
@@ -227,11 +230,13 @@ pub const Register = enum(u8) {
return @as(u8, reg.id());
}
- pub fn bitSize(reg: Register) u32 {
+ pub fn bitSize(reg: Register, zcu: Module) u32 {
+ const features = zcu.getTarget().cpu.features;
+
return switch (@intFromEnum(reg)) {
// zig fmt: off
@intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => 64,
- @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => 32,
+ @intFromEnum(Register.ft0) ... @intFromEnum(Register.f31) => if (Target.riscv.featureSetHas(features, .d)) 64 else 32,
else => unreachable,
// zig fmt: on
};
src/arch/riscv64/CodeGen.zig
@@ -5226,13 +5226,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
const src_reg_class = src_reg.class();
- if (src_reg_class == .float) {
- if (dst_reg_class == .float) {
- return self.fail("TODO: genSetReg float -> float", .{});
- }
-
- assert(dst_reg_class == .int); // a bit of future proofing
-
+ if (src_reg_class == .float and dst_reg_class == .int) {
// to move from float -> int, we use FMV.X.W
return self.fail("TODO: genSetReg float -> int", .{});
}
@@ -6031,6 +6025,7 @@ fn resolveCallingConventionValues(
} else {
var ret_tracking: [2]InstTracking = undefined;
var ret_tracking_i: usize = 0;
+ var ret_float_reg_i: usize = 0;
const classes = mem.sliceTo(&abi.classifySystem(ret_ty, zcu), .none);
@@ -6042,6 +6037,13 @@ fn resolveCallingConventionValues(
ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg });
ret_tracking_i += 1;
},
+ .float => {
+ const ret_float_reg = abi.Registers.Float.function_ret_regs[ret_float_reg_i];
+ ret_float_reg_i += 1;
+
+ ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_float_reg });
+ ret_tracking_i += 1;
+ },
.memory => {
const ret_int_reg = abi.Registers.Integer.function_ret_regs[ret_int_reg_i];
ret_int_reg_i += 1;
@@ -6076,6 +6078,8 @@ fn resolveCallingConventionValues(
var arg_mcv: [2]MCValue = undefined;
var arg_mcv_i: usize = 0;
+ var param_float_reg_i: usize = 0;
+
const classes = mem.sliceTo(&abi.classifySystem(ty, zcu), .none);
for (classes) |class| switch (class) {
@@ -6089,6 +6093,16 @@ fn resolveCallingConventionValues(
arg_mcv[arg_mcv_i] = .{ .register = param_int_reg };
arg_mcv_i += 1;
},
+ .float => {
+ const param_float_regs = abi.Registers.Float.function_arg_regs;
+ if (param_float_reg_i >= param_float_regs.len) break;
+
+ const param_float_reg = param_float_regs[param_float_reg_i];
+ param_float_reg_i += 1;
+
+ arg_mcv[arg_mcv_i] = .{ .register = param_float_reg };
+ arg_mcv_i += 1;
+ },
.memory => {
const param_int_regs = abi.Registers.Integer.function_arg_regs;
@@ -6118,9 +6132,8 @@ fn resolveCallingConventionValues(
return result;
}
-/// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`.
fn wantSafety(self: *Self) bool {
- return switch (self.bin_file.comp.root_mod.optimize_mode) {
+ return switch (self.mod.optimize_mode) {
.Debug => true,
.ReleaseSafe => true,
.ReleaseFast => false,
src/arch/riscv64/Encoding.zig
@@ -124,115 +124,119 @@ pub const Mnemonic = enum {
fsd,
fsw,
+ fsgnjns,
+
pub fn encoding(mnem: Mnemonic) Enc {
return switch (mnem) {
// zig fmt: off
// OP
- .add => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
- .sub => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
+ .add => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
+ .sub => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
- .@"and" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
- .@"or" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
- .xor => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
+ .@"and" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
+ .@"or" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
+ .xor => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
- .sltu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
- .slt => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
+ .sltu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
+ .slt => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
- .mul => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
+ .mul => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
// OP_IMM
- .addi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
- .andi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b111 } } },
- .xori => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b100 } } },
+ .addi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
+ .andi => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b111 } } },
+ .xori => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b100 } } },
- .sltiu => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b011 } } },
+ .sltiu => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b011 } } },
- .slli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b001 } } },
- .srli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101 } } },
- .srai => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101, .offset = 1 << 10 } } },
+ .slli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b001 } } },
+ .srli => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101 } } },
+ .srai => .{ .opcode = .OP_IMM, .data = .{ .fo = .{ .funct3 = 0b101, .offset = 1 << 10 } } },
// OP_FP
- .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
- .faddd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
+ .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
+ .faddd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
+
+ .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
+ .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
- .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
- .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
+ .fsgnjns => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b000 } } },
// LOAD
- .ld => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b011 } } },
- .lw => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b010 } } },
- .lwu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b110 } } },
- .lh => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b001 } } },
- .lhu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b101 } } },
- .lb => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b000 } } },
- .lbu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b100 } } },
+ .ld => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b011 } } },
+ .lw => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b010 } } },
+ .lwu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b110 } } },
+ .lh => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b001 } } },
+ .lhu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b101 } } },
+ .lb => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b000 } } },
+ .lbu => .{ .opcode = .LOAD, .data = .{ .fo = .{ .funct3 = 0b100 } } },
// STORE
- .sd => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b011 } } },
- .sw => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b010 } } },
- .sh => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b001 } } },
- .sb => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
+ .sd => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b011 } } },
+ .sw => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b010 } } },
+ .sh => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b001 } } },
+ .sb => .{ .opcode = .STORE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
// LOAD_FP
- .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
- .flw => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
+ .fld => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
+ .flw => .{ .opcode = .LOAD_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
// STORE_FP
- .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
- .fsw => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
+ .fsd => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b011 } } },
+ .fsw => .{ .opcode = .STORE_FP, .data = .{ .fo = .{ .funct3 = 0b010 } } },
// JALR
- .jalr => .{ .opcode = .JALR, .data = .{ .fo = .{ .funct3 = 0b000 } } },
+ .jalr => .{ .opcode = .JALR, .data = .{ .fo = .{ .funct3 = 0b000 } } },
// OP_32
- .sllw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
+ .sllw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
// LUI
- .lui => .{ .opcode = .LUI, .data = .{ .none = {} } },
+ .lui => .{ .opcode = .LUI, .data = .{ .none = {} } },
// AUIPC
- .auipc => .{ .opcode = .AUIPC, .data = .{ .none = {} } },
+ .auipc => .{ .opcode = .AUIPC, .data = .{ .none = {} } },
// JAL
- .jal => .{ .opcode = .JAL, .data = .{ .none = {} } },
+ .jal => .{ .opcode = .JAL, .data = .{ .none = {} } },
// BRANCH
- .beq => .{ .opcode = .BRANCH, .data = .{ .fo = .{ .funct3 = 0b000 } } },
+ .beq => .{ .opcode = .BRANCH, .data = .{ .fo = .{ .funct3 = 0b000 } } },
// SYSTEM
- .ecall => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
- .ebreak => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
+ .ecall => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
+ .ebreak => .{ .opcode = .SYSTEM, .data = .{ .fo = .{ .funct3 = 0b000 } } },
// NONE
- .unimp => .{ .opcode = .NONE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
+ .unimp => .{ .opcode = .NONE, .data = .{ .fo = .{ .funct3 = 0b000 } } },
// zig fmt: on
@@ -308,6 +312,7 @@ pub const InstEnc = enum {
.faddd,
.feqs,
.feqd,
+ .fsgnjns,
=> .R,
.ecall,
src/arch/riscv64/Lower.zig
@@ -132,11 +132,27 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.pseudo_mv => {
const rr = inst.data.rr;
- try lower.emit(.addi, &.{
- .{ .reg = rr.rd },
- .{ .reg = rr.rs },
- .{ .imm = Immediate.s(0) },
- });
+ const dst_class = rr.rd.class();
+ const src_class = rr.rs.class();
+
+ assert(dst_class == src_class);
+
+ switch (dst_class) {
+ .float => {
+ try lower.emit(.fsgnjns, &.{
+ .{ .reg = rr.rd },
+ .{ .reg = rr.rs },
+ .{ .reg = rr.rs },
+ });
+ },
+ .int => {
+ try lower.emit(.addi, &.{
+ .{ .reg = rr.rd },
+ .{ .reg = rr.rs },
+ .{ .imm = Immediate.s(0) },
+ });
+ },
+ }
},
.pseudo_ret => {
src/codegen/llvm.zig
@@ -11148,7 +11148,6 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu
}
return o.builder.structType(.normal, types[0..types_len]);
},
- .none => unreachable,
}
},
// TODO investigate C ABI for other architectures
@@ -11406,7 +11405,6 @@ const ParamTypeIterator = struct {
it.llvm_index += it.types_len - 1;
return .multiple_llvm_types;
},
- .none => unreachable,
}
},
// TODO investigate C ABI for other architectures