Refactor and check "onlyReadsMemory" before optimizing builtins.

This patch is mostly just refactoring a bunch of copy-and-pasted code, but
it also adds a check that the call instructions are readnone or readonly.
That check was already present for sin, cos, sqrt, log2, and exp2 calls, but
it was missing for the rest of the builtins being handled in this code.

llvm-svn: 161282
This commit is contained in:
Bob Wilson 2012-08-03 23:29:17 +00:00
parent 7713568689
commit 9f6e25017a
13 changed files with 49 additions and 102 deletions

View File

@ -5511,6 +5511,22 @@ bool SelectionDAGBuilder::visitMemCmpCall(const CallInst &I) {
return false;
}
/// visitUnaryFloatCall - If a call instruction is a unary floating-point
/// operation (as expected), translate it to an SDNode with the specified opcode
/// and return true.
bool SelectionDAGBuilder::visitUnaryFloatCall(const CallInst &I,
unsigned Opcode) {
// Sanity check that it really is a unary floating-point call.
if (I.getNumArgOperands() != 1 ||
!I.getArgOperand(0)->getType()->isFloatingPointTy() ||
I.getType() != I.getArgOperand(0)->getType() ||
!I.onlyReadsMemory())
return false;
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(Opcode, getCurDebugLoc(), Tmp.getValueType(), Tmp));
return true;
}
void SelectionDAGBuilder::visitCall(const CallInst &I) {
// Handle inline assembly differently.
@ -5553,7 +5569,8 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) {
if (I.getNumArgOperands() == 2 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType() &&
I.getType() == I.getArgOperand(1)->getType()) {
I.getType() == I.getArgOperand(1)->getType() &&
I.onlyReadsMemory()) {
SDValue LHS = getValue(I.getArgOperand(0));
SDValue RHS = getValue(I.getArgOperand(1));
setValue(&I, DAG.getNode(ISD::FCOPYSIGN, getCurDebugLoc(),
@ -5564,139 +5581,68 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) {
case LibFunc::fabs:
case LibFunc::fabsf:
case LibFunc::fabsl:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FABS, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FABS))
return;
}
break;
case LibFunc::sin:
case LibFunc::sinf:
case LibFunc::sinl:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType() &&
I.onlyReadsMemory()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FSIN, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FSIN))
return;
}
break;
case LibFunc::cos:
case LibFunc::cosf:
case LibFunc::cosl:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType() &&
I.onlyReadsMemory()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FCOS, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FCOS))
return;
}
break;
case LibFunc::sqrt:
case LibFunc::sqrtf:
case LibFunc::sqrtl:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType() &&
I.onlyReadsMemory()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FSQRT, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FSQRT))
return;
}
break;
case LibFunc::floor:
case LibFunc::floorf:
case LibFunc::floorl:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FFLOOR, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FFLOOR))
return;
}
break;
case LibFunc::nearbyint:
case LibFunc::nearbyintf:
case LibFunc::nearbyintl:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FNEARBYINT, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FNEARBYINT))
return;
}
break;
case LibFunc::ceil:
case LibFunc::ceilf:
case LibFunc::ceill:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FCEIL, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FCEIL))
return;
}
break;
case LibFunc::rint:
case LibFunc::rintf:
case LibFunc::rintl:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FRINT, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FRINT))
return;
}
break;
case LibFunc::trunc:
case LibFunc::truncf:
case LibFunc::truncl:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FTRUNC, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FTRUNC))
return;
}
break;
case LibFunc::log2:
case LibFunc::log2f:
case LibFunc::log2l:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType() &&
I.onlyReadsMemory()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FLOG2, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FLOG2))
return;
}
break;
case LibFunc::exp2:
case LibFunc::exp2f:
case LibFunc::exp2l:
if (I.getNumArgOperands() == 1 && // Basic sanity checks.
I.getArgOperand(0)->getType()->isFloatingPointTy() &&
I.getType() == I.getArgOperand(0)->getType() &&
I.onlyReadsMemory()) {
SDValue Tmp = getValue(I.getArgOperand(0));
setValue(&I, DAG.getNode(ISD::FEXP2, getCurDebugLoc(),
Tmp.getValueType(), Tmp));
if (visitUnaryFloatCall(I, ISD::FEXP2))
return;
}
break;
case LibFunc::memcmp:
if (visitMemCmpCall(I))

View File

@ -520,6 +520,7 @@ private:
void visitPHI(const PHINode &I);
void visitCall(const CallInst &I);
bool visitMemCmpCall(const CallInst &I);
bool visitUnaryFloatCall(const CallInst &I, unsigned Opcode);
void visitAtomicLoad(const LoadInst &I);
void visitAtomicStore(const StoreInst &I);

View File

@ -6,7 +6,7 @@
define float @test(float %a, float %b) {
entry:
%dum = fadd float %a, %b
%0 = tail call float @fabsf(float %dum)
%0 = tail call float @fabsf(float %dum) readnone
%dum1 = fadd float %0, %b
ret float %dum1
}

View File

@ -11,7 +11,7 @@ entry:
; HARD: test1:
; HARD: vmov.i32 [[REG1:(d[0-9]+)]], #0x80000000
; HARD: vbsl [[REG1]], d
%0 = tail call float @copysignf(float %x, float %y) nounwind
%0 = tail call float @copysignf(float %x, float %y) nounwind readnone
ret float %0
}
@ -25,7 +25,7 @@ entry:
; HARD: vmov.i32 [[REG2:(d[0-9]+)]], #0x80000000
; HARD: vshl.i64 [[REG2]], [[REG2]], #32
; HARD: vbsl [[REG2]], d1, d0
%0 = tail call double @copysign(double %x, double %y) nounwind
%0 = tail call double @copysign(double %x, double %y) nounwind readnone
ret double %0
}
@ -36,7 +36,7 @@ entry:
; SOFT: vshl.i64 [[REG3]], [[REG3]], #32
; SOFT: vbsl [[REG3]],
%0 = fmul double %x, %y
%1 = tail call double @copysign(double %0, double %z) nounwind
%1 = tail call double @copysign(double %0, double %z) nounwind readnone
ret double %1
}

View File

@ -84,7 +84,7 @@ define float @f11(float %a) {
;CHECK: f11:
;CHECK: bic
entry:
%tmp1 = call float @fabsf( float %a ) ; <float> [#uses=1]
%tmp1 = call float @fabsf( float %a ) readnone ; <float> [#uses=1]
ret float %tmp1
}
@ -94,7 +94,7 @@ define double @f12(double %a) {
;CHECK: f12:
;CHECK: vabs.f64
entry:
%tmp1 = call double @fabs( double %a ) ; <double> [#uses=1]
%tmp1 = call double @fabs( double %a ) readnone ; <double> [#uses=1]
ret double %tmp1
}

View File

@ -17,11 +17,11 @@ define void @test_abs(float* %P, double* %D) {
;CHECK: test_abs:
%a = load float* %P ; <float> [#uses=1]
;CHECK: vabs.f32
%b = call float @fabsf( float %a ) ; <float> [#uses=1]
%b = call float @fabsf( float %a ) readnone ; <float> [#uses=1]
store float %b, float* %P
%A = load double* %D ; <double> [#uses=1]
;CHECK: vabs.f64
%B = call double @fabs( double %A ) ; <double> [#uses=1]
%B = call double @fabs( double %A ) readnone ; <double> [#uses=1]
store double %B, double* %D
ret void
}

View File

@ -15,8 +15,8 @@ define i1 @fcmp_eq(float %arg1, float %arg2) {
define i1 @fcmp_mag_eq(float %arg1, float %arg2) {
; CHECK: fcmeq
; CHECK: bi $lr
%1 = call float @fabsf(float %arg1)
%2 = call float @fabsf(float %arg2)
%1 = call float @fabsf(float %arg1) readnone
%2 = call float @fabsf(float %arg2) readnone
%3 = fcmp oeq float %1, %2
ret i1 %3
}

View File

@ -32,11 +32,11 @@ declare double @fabs(double)
declare float @fabsf(float)
define double @fabs_dp(double %X) {
%Y = call double @fabs( double %X )
%Y = call double @fabs( double %X ) readnone
ret double %Y
}
define float @fabs_sp(float %X) {
%Y = call float @fabsf( float %X )
%Y = call float @fabsf( float %X ) readnone
ret float %Y
}

View File

@ -8,7 +8,7 @@ entry:
%x.addr = alloca float, align 4
store float %x, float* %x.addr, align 4
%0 = load float* %x.addr, align 4
%call = call float @fabsf(float %0)
%call = call float @fabsf(float %0) readnone
ret float %call
}

View File

@ -2,6 +2,6 @@
define double @fabs(double %f) {
entry:
%tmp2 = tail call double @fabs( double %f ) ; <double> [#uses=1]
%tmp2 = tail call double @fabs( double %f ) readnone ; <double> [#uses=1]
ret double %tmp2
}

View File

@ -3,7 +3,7 @@
declare double @fabs(double)
define double @test(double %X) {
%Y = call double @fabs( double %X ) ; <double> [#uses=1]
%Y = call double @fabs( double %X ) readnone ; <double> [#uses=1]
%Z = fsub double -0.000000e+00, %Y ; <double> [#uses=1]
ret double %Z
}

View File

@ -11,7 +11,7 @@ declare x86_fp80 @fabsl(x86_fp80)
; UNSAFE: test1:
; NOOPT: test1:
define float @test1(float %X) {
%Y = call float @fabsf(float %X)
%Y = call float @fabsf(float %X) readnone
ret float %Y
}
; CHECK: {{^[ \t]+fabs$}}
@ -42,7 +42,7 @@ define double @test2(double %X) {
; UNSAFE: test3:
; NOOPT: test3:
define x86_fp80 @test3(x86_fp80 %X) {
%Y = call x86_fp80 @fabsl(x86_fp80 %X)
%Y = call x86_fp80 @fabsl(x86_fp80 %X) readnone
ret x86_fp80 %Y
}
; CHECK: {{^[ \t]+fabs$}}

View File

@ -10,11 +10,11 @@ target triple = "i686-apple-darwin8"
define void @test({ double, double }* byval %z, double* %P) nounwind {
entry:
%tmp3 = load double* @G, align 16 ; <double> [#uses=1]
%tmp4 = tail call double @fabs( double %tmp3 ) ; <double> [#uses=1]
%tmp4 = tail call double @fabs( double %tmp3 ) readnone ; <double> [#uses=1]
store volatile double %tmp4, double* %P
%tmp = getelementptr { double, double }* %z, i32 0, i32 0 ; <double*> [#uses=1]
%tmp1 = load volatile double* %tmp, align 8 ; <double> [#uses=1]
%tmp2 = tail call double @fabs( double %tmp1 ) ; <double> [#uses=1]
%tmp2 = tail call double @fabs( double %tmp1 ) readnone ; <double> [#uses=1]
; CHECK: andpd{{.*}}4(%esp), %xmm
%tmp6 = fadd double %tmp4, %tmp2 ; <double> [#uses=1]
store volatile double %tmp6, double* %P, align 8