Index: lib/Transforms/Scalar/SCCP.cpp =================================================================== --- lib/Transforms/Scalar/SCCP.cpp +++ lib/Transforms/Scalar/SCCP.cpp @@ -270,6 +270,18 @@ return BBExecutable.count(BB); } + std::vector getStructLatticeValueFor(Value *V) const { + std::vector StructValues; + StructType *STy = dyn_cast(V->getType()); + assert(STy && "getStructLatticeValueFor() can be called only on structs"); + for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { + auto I = StructValueState.find(std::make_pair(V, i)); + assert(I != StructValueState.end() && "Value not in valuemap!"); + StructValues.push_back(I->second); + } + return StructValues; + } + LatticeVal getLatticeValueFor(Value *V) const { DenseMap::const_iterator I = ValueState.find(V); assert(I != ValueState.end() && "V is not in valuemap!"); @@ -1545,16 +1557,30 @@ if (Inst->getType()->isVoidTy() || isa(Inst)) continue; - // TODO: Reconstruct structs from their elements. - if (Inst->getType()->isStructTy()) - continue; - - LatticeVal IV = Solver.getLatticeValueFor(Inst); - if (IV.isOverdefined()) - continue; + Constant *Const = nullptr; + if (Inst->getType()->isStructTy()) { + std::vector IVs = Solver.getStructLatticeValueFor(Inst); + if (std::any_of(IVs.begin(), IVs.end(), + [](LatticeVal &LV) { return LV.isOverdefined(); })) + continue; + std::vector ConstVals; + StructType *ST = dyn_cast(Inst->getType()); + for (unsigned i = 0, e = ST->getNumElements(); i != e; ++i) { + LatticeVal V = IVs[i]; + ConstVals.push_back(V.isConstant() + ? V.getConstant() + : UndefValue::get(ST->getElementType(i))); + } + Const = ConstantStruct::get(ST, ConstVals); + } else { + LatticeVal IV = Solver.getLatticeValueFor(Inst); + if (IV.isOverdefined()) + continue; - Constant *Const = IV.isConstant() - ? IV.getConstant() : UndefValue::get(Inst->getType()); + Const = IV.isConstant() ? IV.getConstant() + : UndefValue::get(Inst->getType()); + } + assert(Const && "Constant is nullptr here!"); DEBUG(dbgs() << " Constant: " << *Const << " = " << *Inst << '\n'); // Replaces all of the uses of a variable with uses of the constant. Index: test/Transforms/SCCP/constant-struct.ll =================================================================== --- /dev/null +++ test/Transforms/SCCP/constant-struct.ll @@ -0,0 +1,72 @@ +; Test that constant structs are folded. +; RUN: opt %s -sccp -S | FileCheck %s + +define internal {i64} @struct1() { + %a = insertvalue {i64} undef, i64 24, 0 + ret {i64} %a +} + +; CHECK: define internal { i64 } @struct1() { +; CHECK-NEXT: ret { i64 } { i64 24 } +; CHECK-NEXT: } + +define internal {i64, i64} @struct2() { + %a = insertvalue {i64, i64} undef, i64 24, 0 + ret {i64, i64} %a +} + +; CHECK: define internal { i64, i64 } @struct2() { +; CHECK-NEXT: ret { i64, i64 } { i64 24, i64 undef } +; CHECK-NEXT: } + +define internal {i64, i64, i64} @struct3(i64 %x) { + %a = insertvalue {i64, i64, i64} undef, i64 24, 0 + %b = insertvalue {i64, i64, i64} %a, i64 36, 1 + %c = insertvalue {i64, i64, i64} %b, i64 %x, 2 + ret {i64, i64, i64} %c +} + +; CHECK: define internal { i64, i64, i64 } @struct3(i64 %x) { +; CHECK-NEXT: %c = insertvalue { i64, i64, i64 } { i64 24, i64 36, i64 undef }, i64 %x, 2 +; CHECK-NEXT: ret { i64, i64, i64 } %c +; CHECK-NEXT: } + +; Test(s) for overdefined values. +define internal {i64, i32} @struct4(i32 %x) { + %a = insertvalue {i64, i32} {i64 12, i32 24}, i32 %x, 1 + ret {i64, i32} %a +} + +; CHECK: define internal { i64, i32 } @struct4(i32 %x) { +; CHECK-NEXT: %a = insertvalue { i64, i32 } { i64 12, i32 24 }, i32 %x, 1 +; CHECK-NEXT: ret { i64, i32 } %a +; CHECK-NEXT: } + +define internal {i32} @struct5(i32 %x) { + %a = insertvalue {i32} undef, i32 %x, 0 + ret {i32} %a +} + +; CHECK: define internal { i32 } @struct5(i32 %x) { +; CHECK-NEXT: %a = insertvalue { i32 } undef, i32 %x, 0 +; CHECK-NEXT: ret { i32 } %a +; CHECK-NEXT: } + + +define internal {i32} @struct6({i32} %x) { + %a = insertvalue {i32} %x, i32 12, 0 + ret {i32} %a +} + +; CHECK: define internal { i32 } @struct6({ i32 } %x) { +; CHECK-NEXT: ret { i32 } { i32 12 } +; CHECK-NEXT: } + +define internal {i16} @struct7() { + %a = insertvalue {i16} {i16 4}, i16 7, 0 + ret {i16} %a +} + +; CHECK: define internal { i16 } @struct7() { +; CHECK-NEXT: ret { i16 } { i16 7 } +; CHECK-NEXT: }