diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -507,6 +507,24 @@ return LV; } + LatticeVal toLatticeVal(const ValueLatticeElement &V, Type *T) { + LatticeVal Res; + if (V.isUndefined()) + return Res; + + if (V.isConstant()) { + Res.markConstant(V.getConstant()); + return Res; + } + if (V.isConstantRange() && V.getConstantRange().isSingleElement()) { + Res.markConstant( + ConstantInt::get(T, *V.getConstantRange().getSingleElement())); + return Res; + } + Res.markOverdefined(); + return Res; + } + ValueLatticeElement &getParamState(Value *V) { assert(!V->getType()->isStructTy() && "Should use getStructValueState"); @@ -1329,10 +1347,12 @@ } else { // Most other parts of the Solver still only use the simpler value // lattice, so we propagate changes for parameters to both lattices. - LatticeVal ConcreteArgument = getValueState(*CAI); - bool ParamChanged = - getParamState(&*AI).mergeIn(ConcreteArgument.toValueLattice(), DL); - bool ValueChanged = mergeInValue(&*AI, ConcreteArgument); + ValueLatticeElement ConcreteArgument = + isa(*CAI) ? getParamState(*CAI) + : getValueState(*CAI).toValueLattice(); + bool ParamChanged = getParamState(&*AI).mergeIn(ConcreteArgument, DL); + bool ValueChanged = + mergeInValue(&*AI, toLatticeVal(ConcreteArgument, AI->getType())); // Add argument to work list, if the state of a parameter changes but // ValueState does not change (because it is already overdefined there), // We have to take changes in ParamState into account, as it is used diff --git a/llvm/test/Transforms/SCCP/ip-constant-ranges.ll b/llvm/test/Transforms/SCCP/ip-constant-ranges.ll --- a/llvm/test/Transforms/SCCP/ip-constant-ranges.ll +++ b/llvm/test/Transforms/SCCP/ip-constant-ranges.ll @@ -196,3 +196,41 @@ %call = call i32 @recursive_f(i32 42) ret i32 %call } + +define internal i32 @callee6.1(i32 %i) { +; CHECK-LABEL: define internal i32 @callee6.1( +; CHECK-NEXT: %res = call i32 @callee6.2(i32 %i) +; CHECK-NEXT: ret i32 undef +; + %res = call i32 @callee6.2(i32 %i) + ret i32 %res +} + +define internal i32 @callee6.2(i32 %i) { +; CHECK-LABEL: define internal i32 @callee6.2(i32 %i) { +; CHECK-NEXT: br label %if.then + +; CHECK-LABEL: if.then: +; CHECK-NEXT: ret i32 undef +; + %cmp = icmp ne i32 %i, 0 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + ret i32 1 + +if.else: ; preds = %entry + ret i32 2 +} + +define i32 @caller6() { +; CHECK-LABEL: define i32 @caller6() { +; CHECK-NEXT: %call.1 = call i32 @callee6.1(i32 30) +; CHECK-NEXT: %call.2 = call i32 @callee6.1(i32 43) +; CHECK-NEXT: ret i32 2 + + %call.1 = call i32 @callee6.1(i32 30) + %call.2 = call i32 @callee6.1(i32 43) + %res = add i32 %call.1, %call.2 + ret i32 %res +}