mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-02 08:26:29 +00:00
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:
parent
7713568689
commit
9f6e25017a
@ -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))
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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$}}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user