mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
Recommit "[SCCP] Use SimplifyBinOp for non-integer constant/expressions & overdef."
This includes a fix reported with simplifications in the presence of NaN. This reverts the revert commit 06408451bf12d4baed1fb1312d8af6e6bbb6a797.
This commit is contained in:
parent
90fb14510f
commit
373d0c84dc
@ -28,6 +28,7 @@
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Analysis/ConstantFolding.h"
|
||||
#include "llvm/Analysis/GlobalsModRef.h"
|
||||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/Analysis/ValueLattice.h"
|
||||
#include "llvm/Analysis/ValueLatticeUtils.h"
|
||||
@ -369,8 +370,10 @@ private:
|
||||
// markConstant - Make a value be marked as "constant". If the value
|
||||
// is not already a constant, add it to the instruction work list so that
|
||||
// the users of the instruction are updated later.
|
||||
bool markConstant(ValueLatticeElement &IV, Value *V, Constant *C) {
|
||||
if (!IV.markConstant(C)) return false;
|
||||
bool markConstant(ValueLatticeElement &IV, Value *V, Constant *C,
|
||||
bool MayIncludeUndef = false) {
|
||||
if (!IV.markConstant(C, MayIncludeUndef))
|
||||
return false;
|
||||
LLVM_DEBUG(dbgs() << "markConstant: " << *C << ": " << *V << '\n');
|
||||
pushToWorkList(IV, V);
|
||||
return true;
|
||||
@ -954,23 +957,33 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
|
||||
if (V1State.isOverdefined() && V2State.isOverdefined())
|
||||
return (void)markOverdefined(&I);
|
||||
|
||||
// Both operands are non-integer constants or constant expressions.
|
||||
// If either of the operands is a constant, try to fold it to a constant.
|
||||
// TODO: Use information from notconstant better.
|
||||
if (isConstant(V1State) && isConstant(V2State)) {
|
||||
Constant *C = ConstantExpr::get(I.getOpcode(), getConstant(V1State),
|
||||
getConstant(V2State));
|
||||
// X op Y -> undef.
|
||||
if (isa<UndefValue>(C))
|
||||
return;
|
||||
return (void)markConstant(IV, &I, C);
|
||||
if ((V1State.isConstant() || V2State.isConstant())) {
|
||||
Value *V1 = isConstant(V1State) ? getConstant(V1State) : I.getOperand(0);
|
||||
Value *V2 = isConstant(V2State) ? getConstant(V2State) : I.getOperand(1);
|
||||
Value *R = SimplifyBinOp(I.getOpcode(), V1, V2, SimplifyQuery(DL));
|
||||
auto *C = dyn_cast_or_null<Constant>(R);
|
||||
if (C) {
|
||||
// X op Y -> undef.
|
||||
if (isa<UndefValue>(C))
|
||||
return;
|
||||
// Conservatively assume that the result may be based on operands that may
|
||||
// be undef. Note that we use mergeInValue to combine the constant with
|
||||
// the existing lattice value for I, as different constants might be found
|
||||
// after one of the operands go to overdefined, e.g. due to one operand
|
||||
// being a special floating value.
|
||||
ValueLatticeElement NewV;
|
||||
NewV.markConstant(C, /*MayIncludeUndef=*/true);
|
||||
return (void)mergeInValue(&I, NewV);
|
||||
}
|
||||
}
|
||||
|
||||
// Only use ranges for binary operators on integers.
|
||||
if (!I.getType()->isIntegerTy())
|
||||
return markOverdefined(&I);
|
||||
|
||||
// Operands are either constant ranges, notconstant, overdefined or one of the
|
||||
// operands is a constant.
|
||||
// Try to simplify to a constant range.
|
||||
ConstantRange A = ConstantRange::getFull(I.getType()->getScalarSizeInBits());
|
||||
ConstantRange B = ConstantRange::getFull(I.getType()->getScalarSizeInBits());
|
||||
if (V1State.isConstantRange())
|
||||
|
67
test/Transforms/SCCP/float-nan-simplification.ll
Normal file
67
test/Transforms/SCCP/float-nan-simplification.ll
Normal file
@ -0,0 +1,67 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -sccp -S %s | FileCheck %s
|
||||
|
||||
; When marking the edge from bb2 -> exit as executable first, %p will be NaN
|
||||
; first and %v.1 will simplify to NaN. But when marking bb1 -> exit executable,
|
||||
; %p will we overdefined and %v.1 will be simplified to 0.0. Make sure we go to
|
||||
; overdefined, instead of crashing.
|
||||
; TODO: Can we do better, i.e. choose the 'conservative' 0.0 initially?
|
||||
define float @test1(float %a, i1 %bc) {
|
||||
; CHECK-LABEL: @test1(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 [[BC:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: br label [[EXIT]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: [[P:%.*]] = phi float [ [[A:%.*]], [[BB1]] ], [ 0x7FF8000000000000, [[BB2]] ]
|
||||
; CHECK-NEXT: [[V_1:%.*]] = fmul float [[P]], 0.000000e+00
|
||||
; CHECK-NEXT: [[V_2:%.*]] = fadd float [[V_1]], 0xFFF8000000000000
|
||||
; CHECK-NEXT: ret float [[V_2]]
|
||||
;
|
||||
entry:
|
||||
br i1 %bc, label %bb1, label %bb2
|
||||
|
||||
bb1:
|
||||
br label %exit
|
||||
|
||||
bb2:
|
||||
br label %exit
|
||||
|
||||
exit:
|
||||
%p = phi float [ %a, %bb1 ], [ 0x7FF8000000000000, %bb2 ]
|
||||
%v.1 = fmul float %p, 0.000000e+00
|
||||
%v.2 = fadd float %v.1, 0xFFF8000000000000
|
||||
ret float %v.2
|
||||
}
|
||||
|
||||
; Same as @test1, but with the incoming values switched.
|
||||
define float @test2(float %a, i1 %bc) {
|
||||
; CHECK-LABEL: @test2(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 [[BC:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: br label [[EXIT]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: [[P:%.*]] = phi float [ 0x7FF8000000000000, [[BB1]] ], [ [[A:%.*]], [[BB2]] ]
|
||||
; CHECK-NEXT: [[V_1:%.*]] = fmul float [[P]], 0.000000e+00
|
||||
; CHECK-NEXT: ret float 0xFFF8000000000000
|
||||
;
|
||||
entry:
|
||||
br i1 %bc, label %bb1, label %bb2
|
||||
|
||||
bb1:
|
||||
br label %exit
|
||||
|
||||
bb2:
|
||||
br label %exit
|
||||
|
||||
exit:
|
||||
%p = phi float [ 0x7FF8000000000000, %bb1 ], [ %a, %bb2 ]
|
||||
%v.1 = fmul float %p, 0.000000e+00
|
||||
%v.2 = fadd float %v.1, 0xFFF8000000000000
|
||||
ret float %v.2
|
||||
}
|
@ -3,10 +3,8 @@
|
||||
|
||||
define void @shift_undef_64(i64* %p) {
|
||||
; CHECK-LABEL: @shift_undef_64(
|
||||
; CHECK-NEXT: [[R1:%.*]] = lshr i64 -1, 4294967296
|
||||
; CHECK-NEXT: store i64 [[R1]], i64* [[P:%.*]]
|
||||
; CHECK-NEXT: [[R2:%.*]] = ashr i64 -1, 4294967297
|
||||
; CHECK-NEXT: store i64 [[R2]], i64* [[P]]
|
||||
; CHECK-NEXT: store i64 0, i64* [[P:%.*]]
|
||||
; CHECK-NEXT: store i64 -1, i64* [[P]]
|
||||
; CHECK-NEXT: [[R3:%.*]] = shl i64 -1, 4294967298
|
||||
; CHECK-NEXT: store i64 [[R3]], i64* [[P]]
|
||||
; CHECK-NEXT: ret void
|
||||
@ -25,10 +23,8 @@ define void @shift_undef_64(i64* %p) {
|
||||
|
||||
define void @shift_undef_65(i65* %p) {
|
||||
; CHECK-LABEL: @shift_undef_65(
|
||||
; CHECK-NEXT: [[R1:%.*]] = lshr i65 2, -18446744073709551615
|
||||
; CHECK-NEXT: store i65 [[R1]], i65* [[P:%.*]]
|
||||
; CHECK-NEXT: [[R2:%.*]] = ashr i65 4, -18446744073709551615
|
||||
; CHECK-NEXT: store i65 [[R2]], i65* [[P]]
|
||||
; CHECK-NEXT: store i65 0, i65* [[P:%.*]]
|
||||
; CHECK-NEXT: store i65 0, i65* [[P]]
|
||||
; CHECK-NEXT: [[R3:%.*]] = shl i65 1, -18446744073709551615
|
||||
; CHECK-NEXT: store i65 [[R3]], i65* [[P]]
|
||||
; CHECK-NEXT: ret void
|
||||
@ -47,10 +43,8 @@ define void @shift_undef_65(i65* %p) {
|
||||
|
||||
define void @shift_undef_256(i256* %p) {
|
||||
; CHECK-LABEL: @shift_undef_256(
|
||||
; CHECK-NEXT: [[R1:%.*]] = lshr i256 2, 18446744073709551617
|
||||
; CHECK-NEXT: store i256 [[R1]], i256* [[P:%.*]]
|
||||
; CHECK-NEXT: [[R2:%.*]] = ashr i256 4, 18446744073709551618
|
||||
; CHECK-NEXT: store i256 [[R2]], i256* [[P]]
|
||||
; CHECK-NEXT: store i256 0, i256* [[P:%.*]]
|
||||
; CHECK-NEXT: store i256 0, i256* [[P]]
|
||||
; CHECK-NEXT: [[R3:%.*]] = shl i256 1, 18446744073709551619
|
||||
; CHECK-NEXT: store i256 [[R3]], i256* [[P]]
|
||||
; CHECK-NEXT: ret void
|
||||
@ -69,10 +63,8 @@ define void @shift_undef_256(i256* %p) {
|
||||
|
||||
define void @shift_undef_511(i511* %p) {
|
||||
; CHECK-LABEL: @shift_undef_511(
|
||||
; CHECK-NEXT: [[R1:%.*]] = lshr i511 -1, 1208925819614629174706276
|
||||
; CHECK-NEXT: store i511 [[R1]], i511* [[P:%.*]]
|
||||
; CHECK-NEXT: [[R2:%.*]] = ashr i511 -2, 1208925819614629174706200
|
||||
; CHECK-NEXT: store i511 [[R2]], i511* [[P]]
|
||||
; CHECK-NEXT: store i511 0, i511* [[P:%.*]]
|
||||
; CHECK-NEXT: store i511 -1, i511* [[P]]
|
||||
; CHECK-NEXT: [[R3:%.*]] = shl i511 -3, 1208925819614629174706180
|
||||
; CHECK-NEXT: store i511 [[R3]], i511* [[P]]
|
||||
; CHECK-NEXT: ret void
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32-S128"
|
||||
|
||||
; FIXME: Add back support for handling special values of vector/fp types.
|
||||
; CHECK: store volatile <2 x i64> %and.i119.i, <2 x i64>* %p
|
||||
; CHECK: store volatile <2 x i64> zeroinitializer, <2 x i64>* %p
|
||||
; rdar://11324230
|
||||
|
||||
define void @foo(<2 x i64>* %p) nounwind {
|
||||
|
Loading…
Reference in New Issue
Block a user