Index: llvm/lib/Transforms/Utils/SCCPSolver.cpp =================================================================== --- llvm/lib/Transforms/Utils/SCCPSolver.cpp +++ llvm/lib/Transforms/Utils/SCCPSolver.cpp @@ -17,6 +17,7 @@ #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/ValueLattice.h" #include "llvm/Analysis/ValueLatticeUtils.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/InstVisitor.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" @@ -612,6 +613,7 @@ void visitCastInst(CastInst &I); void visitSelectInst(SelectInst &I); void visitUnaryOperator(Instruction &I); + void visitFreezeInst(FreezeInst &I); void visitBinaryOperator(Instruction &I); void visitCmpInst(CmpInst &I); void visitExtractValueInst(ExtractValueInst &EVI); @@ -1397,6 +1399,25 @@ markOverdefined(&I); } +void SCCPInstVisitor::visitFreezeInst(FreezeInst &I) { + ValueLatticeElement V0State = getValueState(I.getOperand(0)); + ValueLatticeElement &IV = ValueState[&I]; + // resolvedUndefsIn might mark I as overdefined. Bail out, even if we would + // discover a concrete value later. + if (SCCPSolver::isOverdefined(IV)) + return (void)markOverdefined(&I); + + // If something is unknown/undef, wait for it to resolve. + if (V0State.isUnknownOrUndef()) + return; + + if (SCCPSolver::isConstant(V0State) && + isGuaranteedNotToBeUndefOrPoison(getConstant(V0State))) + return (void)markConstant(IV, &I, getConstant(V0State)); + + markOverdefined(&I); +} + // Handle Binary Operators. void SCCPInstVisitor::visitBinaryOperator(Instruction &I) { ValueLatticeElement V1State = getValueState(I.getOperand(0)); Index: llvm/test/Transforms/SCCP/freeze.ll =================================================================== --- llvm/test/Transforms/SCCP/freeze.ll +++ llvm/test/Transforms/SCCP/freeze.ll @@ -1,6 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes=ipsccp -S %s | FileCheck %s +@g = global i64 0 declare void @use(i1) define i1 @freeze_undef_i1() { @@ -39,6 +40,48 @@ ret <2 x i32> %fr } +define i1 @freeze_const_i1() { +; CHECK-LABEL: @freeze_const_i1( +; CHECK-NEXT: ret i1 true +; + %fr = freeze i1 1 + ret i1 %fr +} + +define ptr @freeze_const_ptr() { +; CHECK-LABEL: @freeze_const_ptr( +; CHECK-NEXT: ret ptr inttoptr (i32 256 to ptr) +; + %fr = freeze ptr inttoptr (i32 256 to ptr) + ret ptr %fr +} + +define float @freeze_const_float() { +; CHECK-LABEL: @freeze_const_float( +; CHECK-NEXT: ret float 2.500000e-01 +; + %fr = freeze float 2.500000e-01 + ret float %fr +} + +define <2 x i32> @freeze_const_vector() { +; CHECK-LABEL: @freeze_const_vector( +; CHECK-NEXT: ret <2 x i32> +; + %fr = freeze <2 x i32> + ret <2 x i32> %fr +} + +; make sure we don't constant-propagate values that could potentially be poison +define i64 @maybe_poison() { +; CHECK-LABEL: @maybe_poison( +; CHECK-NEXT: [[FR:%.*]] = freeze i64 add nuw (i64 ptrtoint (ptr @g to i64), i64 123) +; CHECK-NEXT: ret i64 [[FR]] +; + %fr = freeze i64 add nuw (i64 ptrtoint (ptr @g to i64), i64 123) + ret i64 %fr +} + define i1 @propagate_range_from_and_through_freeze(i32 %x, i32 %y) { ; CHECK-LABEL: @propagate_range_from_and_through_freeze( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 3