diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp index c8d7c4de37fc0..0551120daece7 100644 --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -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 @@ class SCCPSolver : public InstVisitor { // 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(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(R); + if (C) { + // X op Y -> undef. + if (isa(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()) diff --git a/llvm/test/Transforms/SCCP/float-nan-simplification.ll b/llvm/test/Transforms/SCCP/float-nan-simplification.ll new file mode 100644 index 0000000000000..1cedbaa69e44a --- /dev/null +++ b/llvm/test/Transforms/SCCP/float-nan-simplification.ll @@ -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 +} diff --git a/llvm/test/Transforms/SCCP/ub-shift.ll b/llvm/test/Transforms/SCCP/ub-shift.ll index 6e15d6b2bccdc..fbcaef422870e 100644 --- a/llvm/test/Transforms/SCCP/ub-shift.ll +++ b/llvm/test/Transforms/SCCP/ub-shift.ll @@ -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 diff --git a/llvm/test/Transforms/SCCP/vector-bitcast.ll b/llvm/test/Transforms/SCCP/vector-bitcast.ll index 35312034c65b8..b032085083c60 100644 --- a/llvm/test/Transforms/SCCP/vector-bitcast.ll +++ b/llvm/test/Transforms/SCCP/vector-bitcast.ll @@ -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 {