Skip to content

Commit 063a56e

Browse files
committed
ARM: make sure FastISel bails on f64 operations for Cortex-M4.
FastISel wasn't checking the isFPOnlySP subtarget feature before emitting double-precision operations, so it got completely invalid CodeGen for doubles on Cortex-M4F. The normal ISel testing wasn't spectacular either so I added a second RUN line to improve that while I was in the area. llvm-svn: 296031
1 parent 5cd9a9b commit 063a56e

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed

llvm/lib/Target/ARM/ARMFastISel.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,8 +1350,10 @@ bool ARMFastISel::ARMEmitCmp(const Value *Src1Value, const Value *Src2Value,
13501350
if (!SrcEVT.isSimple()) return false;
13511351
MVT SrcVT = SrcEVT.getSimpleVT();
13521352

1353-
bool isFloat = (Ty->isFloatTy() || Ty->isDoubleTy());
1354-
if (isFloat && !Subtarget->hasVFP2())
1353+
if (Ty->isFloatTy() && !Subtarget->hasVFP2())
1354+
return false;
1355+
1356+
if (Ty->isDoubleTy() && (!Subtarget->hasVFP2() || Subtarget->isFPOnlySP()))
13551357
return false;
13561358

13571359
// Check to see if the 2nd operand is a constant that we can encode directly
@@ -1501,7 +1503,7 @@ bool ARMFastISel::SelectCmp(const Instruction *I) {
15011503

15021504
bool ARMFastISel::SelectFPExt(const Instruction *I) {
15031505
// Make sure we have VFP and that we're extending float to double.
1504-
if (!Subtarget->hasVFP2()) return false;
1506+
if (!Subtarget->hasVFP2() || Subtarget->isFPOnlySP()) return false;
15051507

15061508
Value *V = I->getOperand(0);
15071509
if (!I->getType()->isDoubleTy() ||
@@ -1520,7 +1522,7 @@ bool ARMFastISel::SelectFPExt(const Instruction *I) {
15201522

15211523
bool ARMFastISel::SelectFPTrunc(const Instruction *I) {
15221524
// Make sure we have VFP and that we're truncating double to float.
1523-
if (!Subtarget->hasVFP2()) return false;
1525+
if (!Subtarget->hasVFP2() || Subtarget->isFPOnlySP()) return false;
15241526

15251527
Value *V = I->getOperand(0);
15261528
if (!(I->getType()->isFloatTy() &&
@@ -1571,7 +1573,8 @@ bool ARMFastISel::SelectIToFP(const Instruction *I, bool isSigned) {
15711573

15721574
unsigned Opc;
15731575
if (Ty->isFloatTy()) Opc = isSigned ? ARM::VSITOS : ARM::VUITOS;
1574-
else if (Ty->isDoubleTy()) Opc = isSigned ? ARM::VSITOD : ARM::VUITOD;
1576+
else if (Ty->isDoubleTy() && !Subtarget->isFPOnlySP())
1577+
Opc = isSigned ? ARM::VSITOD : ARM::VUITOD;
15751578
else return false;
15761579

15771580
unsigned ResultReg = createResultReg(TLI.getRegClassFor(DstVT));
@@ -1596,7 +1599,8 @@ bool ARMFastISel::SelectFPToI(const Instruction *I, bool isSigned) {
15961599
unsigned Opc;
15971600
Type *OpTy = I->getOperand(0)->getType();
15981601
if (OpTy->isFloatTy()) Opc = isSigned ? ARM::VTOSIZS : ARM::VTOUIZS;
1599-
else if (OpTy->isDoubleTy()) Opc = isSigned ? ARM::VTOSIZD : ARM::VTOUIZD;
1602+
else if (OpTy->isDoubleTy() && !Subtarget->isFPOnlySP())
1603+
Opc = isSigned ? ARM::VTOSIZD : ARM::VTOUIZD;
16001604
else return false;
16011605

16021606
// f64->s32/u32 or f32->s32/u32 both need an intermediate f32 reg.
@@ -1800,8 +1804,9 @@ bool ARMFastISel::SelectBinaryFPOp(const Instruction *I, unsigned ISDOpcode) {
18001804
// if we have them.
18011805
// FIXME: It'd be nice to use NEON instructions.
18021806
Type *Ty = I->getType();
1803-
bool isFloat = (Ty->isDoubleTy() || Ty->isFloatTy());
1804-
if (isFloat && !Subtarget->hasVFP2())
1807+
if (Ty->isFloatTy() && !Subtarget->hasVFP2())
1808+
return false;
1809+
if (Ty->isDoubleTy() && (!Subtarget->hasVFP2() || Subtarget->isFPOnlySP()))
18051810
return false;
18061811

18071812
unsigned Opc;

llvm/test/CodeGen/ARM/fp-only-sp.ll

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
; RUN: llc -mtriple=thumbv7em-apple-macho -mcpu=cortex-m4 %s -o - -O0 | FileCheck %s
2+
; RUN: llc -mtriple=thumbv7em-apple-macho -mcpu=cortex-m4 %s -o - | FileCheck %s
3+
4+
; Note: vldr and vstr really do have 64-bit variants even with fp-only-sp
5+
define void @test_load_store(double* %addr) {
6+
; CHECK-LABEL: test_load_store:
7+
; CHECK: vldr [[TMP:d[0-9]+]], [r0]
8+
; CHECK: vstr [[TMP]], [r0]
9+
%val = load volatile double, double* %addr
10+
store volatile double %val, double* %addr
11+
ret void
12+
}
13+
14+
define void @test_cmp(double %l, double %r, i1* %addr.dst) {
15+
; CHECK-LABEL: test_cmp:
16+
; CHECK: bl ___eqdf2
17+
%res = fcmp oeq double %l, %r
18+
store i1 %res, i1* %addr.dst
19+
ret void
20+
}
21+
22+
define void @test_ext(float %in, double* %addr) {
23+
; CHECK-LABEL: test_ext:
24+
; CHECK: bl ___extendsfdf2
25+
%res = fpext float %in to double
26+
store double %res, double* %addr
27+
ret void
28+
}
29+
30+
define void @test_trunc(double %in, float* %addr) {
31+
; CHECK-LABEL: test_trunc:
32+
; CHECK: bl ___truncdfsf2
33+
%res = fptrunc double %in to float
34+
store float %res, float* %addr
35+
ret void
36+
}
37+
38+
define void @test_itofp(i32 %in, double* %addr) {
39+
; CHECK-LABEL: test_itofp:
40+
; CHECK: bl ___floatsidf
41+
%res = sitofp i32 %in to double
42+
store double %res, double* %addr
43+
; %res = fptoui double %tmp to i32
44+
ret void
45+
}
46+
47+
define i32 @test_fptoi(double* %addr) {
48+
; CHECK-LABEL: test_fptoi:
49+
; CHECK: bl ___fixunsdfsi
50+
%val = load double, double* %addr
51+
%res = fptoui double %val to i32
52+
ret i32 %res
53+
}
54+
55+
define void @test_binop(double* %addr) {
56+
; CHECK-LABEL: test_binop:
57+
; CHECK: bl ___adddf3
58+
%in = load double, double* %addr
59+
%res = fadd double %in, %in
60+
store double %res, double* %addr
61+
ret void
62+
}

0 commit comments

Comments
 (0)