diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 368ceb08be..7b44bcfc7c 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/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, diff --git a/src/arch/riscv64/Encoding.zig b/src/arch/riscv64/Encoding.zig index eec4320753..bbea73aac9 100644 --- a/src/arch/riscv64/Encoding.zig +++ b/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, diff --git a/src/arch/riscv64/Lower.zig b/src/arch/riscv64/Lower.zig index 659d4eb605..6e2fc125cf 100644 --- a/src/arch/riscv64/Lower.zig +++ b/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 => { diff --git a/src/arch/riscv64/abi.zig b/src/arch/riscv64/abi.zig index 88a09d2a50..b8254b68a5 100644 --- a/src/arch/riscv64/abi.zig +++ b/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); diff --git a/src/arch/riscv64/bits.zig b/src/arch/riscv64/bits.zig index 6264ec1854..6b3a61578f 100644 --- a/src/arch/riscv64/bits.zig +++ b/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 }; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index fe7f98bc8d..edf0891a69 100644 --- a/src/codegen/llvm.zig +++ b/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