return BBExecutable.count(BB);
}
+ std::vector<LatticeVal> getStructLatticeValueFor(Value *V) const {
+ std::vector<LatticeVal> StructValues;
+ StructType *STy = dyn_cast<StructType>(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<Value*, LatticeVal>::const_iterator I = ValueState.find(V);
assert(I != ValueState.end() && "V is not in valuemap!");
if (Inst->getType()->isVoidTy() || isa<TerminatorInst>(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<LatticeVal> IVs = Solver.getStructLatticeValueFor(Inst);
+ if (std::any_of(IVs.begin(), IVs.end(),
+ [](LatticeVal &LV) { return LV.isOverdefined(); }))
+ continue;
+ std::vector<Constant *> ConstVals;
+ StructType *ST = dyn_cast<StructType>(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.
--- /dev/null
+; 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: }