Index: lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -305,24 +305,20 @@ return visitAllocSite(AI); } -/// \brief Helper to combine a load to a new type. +/// \brief Helper to combine a load to a new value. /// -/// This just does the work of combining a load to a new type. It handles +/// This just does the work of combining a load to a new value. It handles /// metadata, etc., and returns the new instruction. The \c NewTy should be the -/// loaded *value* type. This will convert it to a pointer, cast the operand to -/// that pointer type, load it, etc. +/// loaded *value* type. /// /// Note that this will create all of the instructions with whatever insert /// point the \c InstCombiner currently is using. -static LoadInst *combineLoadToNewType(InstCombiner &IC, LoadInst &LI, Type *NewTy) { - Value *Ptr = LI.getPointerOperand(); - unsigned AS = LI.getPointerAddressSpace(); +static LoadInst *combineLoadToNewValue(InstCombiner &IC, LoadInst &LI, Value *V, Type *NewTy) { SmallVector, 8> MD; LI.getAllMetadata(MD); LoadInst *NewLoad = IC.Builder->CreateAlignedLoad( - IC.Builder->CreateBitCast(Ptr, NewTy->getPointerTo(AS)), - LI.getAlignment(), LI.getName()); + V, LI.getAlignment(), LI.getName()); MDBuilder MDB(NewLoad->getContext()); for (const auto &MDPair : MD) { unsigned ID = MDPair.first; @@ -358,6 +354,7 @@ // If it's integral now, translate it to !range metadata. if (NewTy->isIntegerTy()) { auto *ITy = cast(NewTy); + Value *Ptr = LI.getPointerOperand(); auto *NullInt = ConstantExpr::getPtrToInt( ConstantPointerNull::get(cast(Ptr->getType())), ITy); auto *NonNullInt = @@ -377,6 +374,23 @@ return NewLoad; } +/// \brief Helper to combine a load to a new type. +/// +/// This just does the work of combining a load to a new type. It handles +/// metadata, etc., and returns the new instruction. The \c NewTy should be the +/// loaded *value* type. This will convert it to a pointer, cast the operand to +/// that pointer type, load it, etc. +/// +/// Note that this will create all of the instructions with whatever insert +/// point the \c InstCombiner currently is using. +static LoadInst *combineLoadToNewType(InstCombiner &IC, LoadInst &LI, Type *NewTy) { + Value *Ptr = LI.getPointerOperand(); + unsigned AS = LI.getPointerAddressSpace(); + + Value *V = IC.Builder->CreateBitCast(Ptr, NewTy->getPointerTo(AS)); + return combineLoadToNewValue(IC, LI, V, NewTy); +} + /// \brief Combine a store to a new type. /// /// Returns the newly created store instruction. @@ -495,6 +509,34 @@ return nullptr; } +static Instruction *unpackLoadToAggregate(InstCombiner &IC, LoadInst &LI) { + // FIXME: We could probably with some care handle both volatile and atomic + // stores here but it isn't clear that this is important. + if (!LI.isSimple()) + return nullptr; + + Value *Ptr = LI.getPointerOperand(); + Type *T = cast(Ptr->getType())->getElementType(); + + if (!T->isAggregateType()) + return nullptr; + + if (StructType *ST = dyn_cast(T)) { + // If the struct only have one element, we unpack. + if (ST->getNumElements() == 1) { + Ptr = IC.Builder->CreateStructGEP(Ptr, 0); + LoadInst *NewLoad = combineLoadToNewValue(IC, LI, Ptr, T); + + Instruction *V = InsertValueInst::Create(UndefValue::get(T), NewLoad, 0); + + LI.replaceAllUsesWith(V); + return V; + } + } + + return nullptr; +} + // If we can determine that all possible objects pointed to by the provided // pointer value are, not only dereferenceable, but also definitively less than // or equal to the provided maximum size, then return true. Otherwise, return @@ -689,6 +731,9 @@ else if (LoadAlign == 0) LI.setAlignment(EffectiveLoadAlign); + if (Instruction *Res = unpackLoadToAggregate(*this, LI)) + return Res; + // Replace GEP indices if possible. if (Instruction *NewGEPI = replaceGEPIdxWithZero(*this, Op, LI)) { Worklist.Add(NewGEPI); Index: test/Transforms/InstCombine/unpack-fca.ll =================================================================== --- test/Transforms/InstCombine/unpack-fca.ll +++ test/Transforms/InstCombine/unpack-fca.ll @@ -12,7 +12,7 @@ declare i8* @allocmemory(i64) -define void @structA() { +define void @storeA() { body: %0 = tail call i8* @allocmemory(i64 32) %1 = bitcast i8* %0 to %A* @@ -21,7 +21,7 @@ ret void } -define void @structOfA() { +define void @storeStructOfA() { body: %0 = tail call i8* @allocmemory(i64 32) %1 = bitcast i8* %0 to { %A }* @@ -29,3 +29,35 @@ store { %A } { %A { %A__vtbl* @A__vtblZ } }, { %A }* %1, align 8 ret void } + +define %A @loadA() { +body: + %0 = tail call i8* @allocmemory(i64 32) + %1 = bitcast i8* %0 to %A* +; CHECK: load %A__vtbl*, +; CHECK: insertvalue %A undef, %A__vtbl* {{.*}}, 0 + %2 = load %A, %A* %1, align 8 + ret %A %2 +} + +define { %A } @loadStructOfA() { +body: + %0 = tail call i8* @allocmemory(i64 32) + %1 = bitcast i8* %0 to { %A }* +; CHECK: load %A__vtbl*, +; CHECK: insertvalue %A undef, %A__vtbl* {{.*}}, 0 +; CHECK: insertvalue { %A } undef, %A {{.*}}, 0 + %2 = load { %A }, { %A }* %1, align 8 + ret { %A } %2 +} + +define { %A } @structOfA() { +body: + %0 = tail call i8* @allocmemory(i64 32) + %1 = bitcast i8* %0 to { %A }* +; CHECK: store %A__vtbl* @A__vtblZ + store { %A } { %A { %A__vtbl* @A__vtblZ } }, { %A }* %1, align 8 + %2 = load { %A }, { %A }* %1, align 8 +; CHECK: ret { %A } { %A { %A__vtbl* @A__vtblZ } } + ret { %A } %2 +}