Skip to content

Commit 2a030d8

Browse files
committed
[MIPS][float] Fixed SingleFloat codegen on N32/N64 targets
1 parent ad31366 commit 2a030d8

12 files changed

+770
-41
lines changed

llvm/lib/Target/Mips/MipsCallingConv.td

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ def RetCC_MipsN : CallingConv<[
196196
//
197197
// f128 should only occur for the N64 ABI where long double is 128-bit. On
198198
// N32, long double is equivalent to double.
199-
CCIfType<[i64], CCIfOrigArgWasF128<CCDelegateTo<RetCC_F128>>>,
199+
CCIfSubtargetNot<"isSingleFloat()",
200+
CCIfType<[i64], CCIfOrigArgWasF128<CCDelegateTo<RetCC_F128>>>>,
200201

201202
// Aggregate returns are positioned at the lowest address in the slot for
202203
// both little and big-endian targets. When passing in registers, this
@@ -333,9 +334,10 @@ def CC_Mips_FixedArg : CallingConv<[
333334
//
334335
// f128 should only occur for the N64 ABI where long double is 128-bit. On
335336
// N32, long double is equivalent to double.
336-
CCIfType<[i64],
337-
CCIfSubtargetNot<"useSoftFloat()",
338-
CCIfOrigArgWasF128<CCBitConvertToType<f64>>>>,
337+
CCIfType<[i64],
338+
CCIfSubtargetNot<"isSingleFloat()",
339+
CCIfSubtargetNot<"useSoftFloat()",
340+
CCIfOrigArgWasF128<CCBitConvertToType<f64>>>>>,
339341

340342
CCIfCC<"CallingConv::Fast", CCDelegateTo<CC_Mips_FastCC>>,
341343

@@ -359,8 +361,8 @@ def CC_Mips : CallingConv<[
359361
// Callee-saved register lists.
360362
//===----------------------------------------------------------------------===//
361363

362-
def CSR_SingleFloatOnly : CalleeSavedRegs<(add (sequence "F%u", 31, 20), RA, FP,
363-
(sequence "S%u", 7, 0))>;
364+
def CSR_O32_SingleFloat : CalleeSavedRegs<(add(sequence "F%u", 31, 20), RA, FP,
365+
(sequence "S%u", 7, 0))>;
364366

365367
def CSR_O32_FPXX : CalleeSavedRegs<(add (sequence "D%u", 15, 10), RA, FP,
366368
(sequence "S%u", 7, 0))> {
@@ -374,13 +376,19 @@ def CSR_O32_FP64 :
374376
CalleeSavedRegs<(add (decimate (sequence "D%u_64", 30, 20), 2), RA, FP,
375377
(sequence "S%u", 7, 0))>;
376378

377-
def CSR_N32 : CalleeSavedRegs<(add D20_64, D22_64, D24_64, D26_64, D28_64,
378-
D30_64, RA_64, FP_64, GP_64,
379-
(sequence "S%u_64", 7, 0))>;
379+
def CSR_N32 : CalleeSavedRegs<(add(decimate(sequence "D%u_64", 30, 20), 2),
380+
RA_64, FP_64, GP_64, (sequence "S%u_64", 7, 0))>;
381+
382+
def CSR_N32_SingleFloat
383+
: CalleeSavedRegs<(add(decimate(sequence "F%u", 30, 20), 2), RA_64, FP_64,
384+
GP_64, (sequence "S%u_64", 7, 0))>;
380385

381386
def CSR_N64 : CalleeSavedRegs<(add (sequence "D%u_64", 31, 24), RA_64, FP_64,
382387
GP_64, (sequence "S%u_64", 7, 0))>;
383388

389+
def CSR_N64_SingleFloat : CalleeSavedRegs<(add(sequence "F%u", 31, 24), RA_64,
390+
FP_64, GP_64, (sequence "S%u_64", 7, 0))>;
391+
384392
def CSR_Mips16RetHelper :
385393
CalleeSavedRegs<(add V0, V1, FP,
386394
(sequence "A%u", 3, 0), (sequence "S%u", 7, 0),

llvm/lib/Target/Mips/MipsISelLowering.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4295,10 +4295,16 @@ parseRegForInlineAsmConstraint(StringRef C, MVT VT) const {
42954295
return std::make_pair(0U, nullptr);
42964296

42974297
if (Prefix == "$f") { // Parse $f0-$f31.
4298-
// If the size of FP registers is 64-bit or Reg is an even number, select
4299-
// the 64-bit register class. Otherwise, select the 32-bit register class.
4300-
if (VT == MVT::Other)
4301-
VT = (Subtarget.isFP64bit() || !(Reg % 2)) ? MVT::f64 : MVT::f32;
4298+
// If the targets is single float only, always select 32-bit registers,
4299+
// otherwise if the size of FP registers is 64-bit or Reg is an even number,
4300+
// select the 64-bit register class. Otherwise, select the 32-bit register
4301+
// class.
4302+
if (VT == MVT::Other) {
4303+
if (Subtarget.isSingleFloat())
4304+
VT = MVT::f32;
4305+
else
4306+
VT = (Subtarget.isFP64bit() || !(Reg % 2)) ? MVT::f64 : MVT::f32;
4307+
}
43024308

43034309
RC = getRegClassFor(VT);
43044310

@@ -4338,10 +4344,12 @@ MipsTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
43384344
return std::make_pair(0U, &Mips::CPU16RegsRegClass);
43394345
return std::make_pair(0U, &Mips::GPR32RegClass);
43404346
}
4341-
if ((VT == MVT::i64 || (VT == MVT::f64 && Subtarget.useSoftFloat())) &&
4347+
if ((VT == MVT::i64 || (VT == MVT::f64 && Subtarget.useSoftFloat()) ||
4348+
(VT == MVT::f64 && Subtarget.isSingleFloat())) &&
43424349
!Subtarget.isGP64bit())
43434350
return std::make_pair(0U, &Mips::GPR32RegClass);
4344-
if ((VT == MVT::i64 || (VT == MVT::f64 && Subtarget.useSoftFloat())) &&
4351+
if ((VT == MVT::i64 || (VT == MVT::f64 && Subtarget.useSoftFloat()) ||
4352+
(VT == MVT::f64 && Subtarget.isSingleFloat())) &&
43454353
Subtarget.isGP64bit())
43464354
return std::make_pair(0U, &Mips::GPR64RegClass);
43474355
// This will generate an error message

llvm/lib/Target/Mips/MipsRegisterInfo.cpp

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,25 @@ MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
102102
: CSR_Interrupt_32_SaveList;
103103
}
104104

105-
if (Subtarget.isSingleFloat())
106-
return CSR_SingleFloatOnly_SaveList;
105+
// N64 ABI
106+
if (Subtarget.isABI_N64()) {
107+
if (Subtarget.isSingleFloat())
108+
return CSR_N64_SingleFloat_SaveList;
107109

108-
if (Subtarget.isABI_N64())
109110
return CSR_N64_SaveList;
111+
}
112+
113+
// N32 ABI
114+
if (Subtarget.isABI_N32()) {
115+
if (Subtarget.isSingleFloat())
116+
return CSR_N32_SingleFloat_SaveList;
110117

111-
if (Subtarget.isABI_N32())
112118
return CSR_N32_SaveList;
119+
}
120+
121+
// O32 ABI
122+
if (Subtarget.isSingleFloat())
123+
return CSR_O32_SingleFloat_SaveList;
113124

114125
if (Subtarget.isFP64bit())
115126
return CSR_O32_FP64_SaveList;
@@ -124,14 +135,25 @@ const uint32_t *
124135
MipsRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
125136
CallingConv::ID) const {
126137
const MipsSubtarget &Subtarget = MF.getSubtarget<MipsSubtarget>();
127-
if (Subtarget.isSingleFloat())
128-
return CSR_SingleFloatOnly_RegMask;
138+
// N64 ABI
139+
if (Subtarget.isABI_N64()) {
140+
if (Subtarget.isSingleFloat())
141+
return CSR_N64_SingleFloat_RegMask;
129142

130-
if (Subtarget.isABI_N64())
131143
return CSR_N64_RegMask;
144+
}
145+
146+
// N32 ABI
147+
if (Subtarget.isABI_N32()) {
148+
if (Subtarget.isSingleFloat())
149+
return CSR_N32_SingleFloat_RegMask;
132150

133-
if (Subtarget.isABI_N32())
134151
return CSR_N32_RegMask;
152+
}
153+
154+
// O32 ABI
155+
if (Subtarget.isSingleFloat())
156+
return CSR_O32_SingleFloat_RegMask;
135157

136158
if (Subtarget.isFP64bit())
137159
return CSR_O32_FP64_RegMask;

llvm/lib/Target/Mips/MipsSEISelLowering.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "llvm/CodeGen/SelectionDAG.h"
2929
#include "llvm/CodeGen/SelectionDAGNodes.h"
3030
#include "llvm/CodeGen/TargetInstrInfo.h"
31+
#include "llvm/CodeGen/TargetLowering.h"
3132
#include "llvm/CodeGen/TargetSubtargetInfo.h"
3233
#include "llvm/CodeGen/ValueTypes.h"
3334
#include "llvm/CodeGenTypes/MachineValueType.h"
@@ -211,6 +212,20 @@ MipsSETargetLowering::MipsSETargetLowering(const MipsTargetMachine &TM,
211212
}
212213
}
213214

215+
// Targets with 64bits integer registers, but no 64bit floating point register
216+
// do not support conversion between them
217+
if (Subtarget.isGP64bit() && Subtarget.isSingleFloat() &&
218+
!Subtarget.useSoftFloat()) {
219+
setOperationAction(ISD::FP_TO_SINT, MVT::i64, Expand);
220+
setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand);
221+
setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i64, Expand);
222+
setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::i64, Expand);
223+
setOperationAction(ISD::SINT_TO_FP, MVT::i64, Expand);
224+
setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand);
225+
setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i64, Expand);
226+
setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i64, Expand);
227+
}
228+
214229
setOperationAction(ISD::SMUL_LOHI, MVT::i32, Custom);
215230
setOperationAction(ISD::UMUL_LOHI, MVT::i32, Custom);
216231
setOperationAction(ISD::MULHS, MVT::i32, Custom);
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
; RUN: llc -mtriple=mips -relocation-model=static -mattr=single-float < %s \
2+
; RUN: | FileCheck --check-prefixes=ALL,SYM32,O32 %s
3+
; RUN: llc -mtriple=mipsel -relocation-model=static -mattr=single-float < %s \
4+
; RUN: | FileCheck --check-prefixes=ALL,SYM32,O32 %s
5+
6+
; RUN: llc -mtriple=mips64 -relocation-model=static -target-abi n32 -mattr=single-float < %s \
7+
; RUN: | FileCheck --check-prefixes=ALL,SYM32,N32,NEW,NEWBE %s
8+
; RUN: llc -mtriple=mips64el -relocation-model=static -target-abi n32 -mattr=single-float < %s \
9+
; RUN: | FileCheck --check-prefixes=ALL,SYM32,N32,NEW,NEWLE %s
10+
11+
; RUN: llc -mtriple=mips64 -relocation-model=static -target-abi n64 -mattr=single-float < %s \
12+
; RUN: | FileCheck --check-prefixes=ALL,SYM64,N64,NEW,NEWBE %s
13+
; RUN: llc -mtriple=mips64el -relocation-model=static -target-abi n64 -mattr=single-float < %s \
14+
; RUN: | FileCheck --check-prefixes=ALL,SYM64,N64,NEW,NEWLE %s
15+
16+
@floats = global [11 x float] zeroinitializer
17+
@doubles = global [11 x double] zeroinitializer
18+
19+
define void @double_args(double %a, ...)
20+
nounwind {
21+
entry:
22+
%0 = getelementptr [11 x double], ptr @doubles, i32 0, i32 1
23+
store volatile double %a, ptr %0
24+
25+
%ap = alloca ptr
26+
call void @llvm.va_start(ptr %ap)
27+
%b = va_arg ptr %ap, double
28+
%1 = getelementptr [11 x double], ptr @doubles, i32 0, i32 2
29+
store volatile double %b, ptr %1
30+
call void @llvm.va_end(ptr %ap)
31+
ret void
32+
}
33+
34+
; ALL-LABEL: double_args:
35+
; We won't test the way the global address is calculated in this test. This is
36+
; just to get the register number for the other checks.
37+
; SYM32-DAG: addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(doubles)
38+
; SYM64-DAG: daddiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(doubles)
39+
40+
; O32 forbids using floating point registers for the non-variable portion.
41+
; N32/N64 allow it.
42+
; O32-DAG: sw $4, 8([[R2]])
43+
; O32-DAG: sw $5, 12([[R2]])
44+
; NEW-DAG: sd $4, 8([[R2]])
45+
46+
; The varargs portion is dumped to stack
47+
; O32-DAG: sw $6, 16($sp)
48+
; O32-DAG: sw $7, 20($sp)
49+
; NEW-DAG: sd $5, 8($sp)
50+
; NEW-DAG: sd $6, 16($sp)
51+
; NEW-DAG: sd $7, 24($sp)
52+
; NEW-DAG: sd $8, 32($sp)
53+
; NEW-DAG: sd $9, 40($sp)
54+
; NEW-DAG: sd $10, 48($sp)
55+
; NEW-DAG: sd $11, 56($sp)
56+
57+
; Get the varargs pointer
58+
; O32 has 4 bytes padding, 4 bytes for the varargs pointer, and 8 bytes reserved
59+
; for arguments 1 and 2.
60+
; N32/N64 has 8 bytes for the varargs pointer, and no reserved area.
61+
; O32-DAG: addiu [[VAPTR:\$[0-9]+]], $sp, 16
62+
; O32-DAG: sw [[VAPTR]], 4($sp)
63+
; N32-DAG: addiu [[VAPTR:\$[0-9]+]], $sp, 8
64+
; N32-DAG: sw [[VAPTR]], 4($sp)
65+
; N64-DAG: daddiu [[VAPTR:\$[0-9]+]], $sp, 8
66+
; N64-DAG: sd [[VAPTR]], 0($sp)
67+
68+
; Increment the pointer then get the varargs arg
69+
; LLVM will rebind the load to the stack pointer instead of the varargs pointer
70+
; during lowering. This is fine and doesn't change the behaviour.
71+
; O32-DAG: addiu [[VAPTR]], [[VAPTR]], 8
72+
; N32-DAG: addiu [[VAPTR]], [[VAPTR]], 8
73+
; N64-DAG: daddiu [[VAPTR]], [[VAPTR]], 8
74+
; O32-DAG: lw [[R3:\$[0-9]+]], 16($sp)
75+
; O32-DAG: lw [[R4:\$[0-9]+]], 20($sp)
76+
; O32-DAG: sw [[R3]], 16([[R2]])
77+
; O32-DAG: sw [[R4]], 20([[R2]])
78+
; NEW-DAG: ld [[R3:\$[0-9]+]], 8($sp)
79+
; NEW-DAG: sd [[R3]], 16([[R2]])
80+
81+
define void @float_args(float %a, ...) nounwind {
82+
entry:
83+
%0 = getelementptr [11 x float], ptr @floats, i32 0, i32 1
84+
store volatile float %a, ptr %0
85+
86+
%ap = alloca ptr
87+
call void @llvm.va_start(ptr %ap)
88+
%b = va_arg ptr %ap, float
89+
%1 = getelementptr [11 x float], ptr @floats, i32 0, i32 2
90+
store volatile float %b, ptr %1
91+
call void @llvm.va_end(ptr %ap)
92+
ret void
93+
}
94+
95+
; ALL-LABEL: float_args:
96+
; We won't test the way the global address is calculated in this test. This is
97+
; just to get the register number for the other checks.
98+
; SYM32-DAG: addiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(floats)
99+
; SYM64-DAG: daddiu [[R2:\$[0-9]+]], ${{[0-9]+}}, %lo(floats)
100+
101+
; The first four arguments are the same in O32/N32/N64.
102+
; The non-variable portion should be unaffected.
103+
; O32-DAG: mtc1 $4, $f0
104+
; O32-DAG: swc1 $f0, 4([[R2]])
105+
; NEW-DAG: swc1 $f12, 4([[R2]])
106+
107+
; The varargs portion is dumped to stack
108+
; O32-DAG: sw $5, 12($sp)
109+
; O32-DAG: sw $6, 16($sp)
110+
; O32-DAG: sw $7, 20($sp)
111+
; NEW-DAG: sd $5, 8($sp)
112+
; NEW-DAG: sd $6, 16($sp)
113+
; NEW-DAG: sd $7, 24($sp)
114+
; NEW-DAG: sd $8, 32($sp)
115+
; NEW-DAG: sd $9, 40($sp)
116+
; NEW-DAG: sd $10, 48($sp)
117+
; NEW-DAG: sd $11, 56($sp)
118+
119+
; Get the varargs pointer
120+
; O32 has 4 bytes padding, 4 bytes for the varargs pointer, and should have 8
121+
; bytes reserved for arguments 1 and 2 (the first float arg) but as discussed in
122+
; arguments-float.ll, GCC doesn't agree with MD00305 and treats floats as 4
123+
; bytes so we only have 12 bytes total.
124+
; N32/N64 has 8 bytes for the varargs pointer, and no reserved area.
125+
; O32-DAG: addiu [[VAPTR:\$[0-9]+]], $sp, 12
126+
; O32-DAG: sw [[VAPTR]], 4($sp)
127+
; N32-DAG: addiu [[VAPTR:\$[0-9]+]], $sp, 8
128+
; N32-DAG: sw [[VAPTR]], 4($sp)
129+
; N64-DAG: daddiu [[VAPTR:\$[0-9]+]], $sp, 8
130+
; N64-DAG: sd [[VAPTR]], 0($sp)
131+
132+
; Increment the pointer then get the varargs arg
133+
; LLVM will rebind the load to the stack pointer instead of the varargs pointer
134+
; during lowering. This is fine and doesn't change the behaviour.
135+
; Also, in big-endian mode the offset must be increased by 4 to retrieve the
136+
; correct half of the argument slot.
137+
;
138+
; O32-DAG: addiu [[VAPTR]], [[VAPTR]], 4
139+
; N32-DAG: addiu [[VAPTR]], [[VAPTR]], 8
140+
; N64-DAG: daddiu [[VAPTR]], [[VAPTR]], 8
141+
; O32-DAG: lwc1 [[FTMP1:\$f[0-9]+]], 12($sp)
142+
; NEWLE-DAG: lwc1 [[FTMP1:\$f[0-9]+]], 8($sp)
143+
; NEWBE-DAG: lwc1 [[FTMP1:\$f[0-9]+]], 12($sp)
144+
; ALL-DAG: swc1 [[FTMP1]], 8([[R2]])
145+
146+
declare void @llvm.va_start(ptr)
147+
declare void @llvm.va_copy(ptr, ptr)
148+
declare void @llvm.va_end(ptr)

0 commit comments

Comments
 (0)