diff --git a/llvm/lib/Transforms/Scalar/NewGVN.cpp b/llvm/lib/Transforms/Scalar/NewGVN.cpp --- a/llvm/lib/Transforms/Scalar/NewGVN.cpp +++ b/llvm/lib/Transforms/Scalar/NewGVN.cpp @@ -656,6 +656,15 @@ // Deletion info. SmallPtrSet InstructionsToErase; + // Keeps the memory instructions that should be optimized with load coercion. + // The first value is the load instruction that should be optimized and the + // second value is the memory access of the memory instruction that the load + // depends on. + std::map LoadCoercion; + + // Keeps the load instructions that have been optimized with load coercion. + SmallPtrSet OptimizedLoads; + public: NewGVN(Function &F, DominatorTree *DT, AssumptionCache *AC, TargetLibraryInfo *TLI, AliasAnalysis *AA, MemorySSA *MSSA, @@ -833,6 +842,7 @@ SmallVectorImpl &) const; bool eliminateInstructions(Function &); + bool implementLoadCoercion(); void replaceInstruction(Instruction *, Value *); void markInstructionForDeletion(Instruction *); void deleteInstructionsInBlock(BasicBlock *); @@ -1456,6 +1466,14 @@ << " to constant " << *C << "\n"); return createConstantExpression( getConstantStoreValueForLoad(C, Offset, LoadType, DL)); + } else { + // Add the load instructions that can be optimized with load coercion in + // LoadCoercion map. + const_cast(this)->LoadCoercion[LI] = DefiningAccess; + // Load coercion occurs before the elimination phase. The loads that can + // be optimized with load coercion are not added in any congruence + // class. Thus, we do not create any load expression for them. + return nullptr; } } } else if (auto *DepLI = dyn_cast(DepInst)) { @@ -2977,6 +2995,8 @@ MemoryToUsers.clear(); RevisitOnReachabilityChange.clear(); IntrinsicInstPred.clear(); + LoadCoercion.clear(); + OptimizedLoads.clear(); } // Assign local DFS number mapping to instructions, and leave space for Value @@ -3481,6 +3501,17 @@ verifyIterationSettled(F); verifyStoreExpressions(); + // During load coercion, we replace the candidate load instructions with a new + // sequence of instructions. Next, we run value numbering which adds the new + // instructions in the right congruence classes. In this way, any redundant + // instructions will be optimized away in the elimiantion phase. Hence, it + // makes sense to do the load coercion before the elimination phase. + if (implementLoadCoercion()) + // The newly generated instructions need to get a DFS number for the + // elimination phase. + // TODO: Update DFS numbers faster. + ICount = updateDFSNumbers(ICount); + Changed |= eliminateInstructions(F); // Delete all instructions marked for deletion. @@ -3816,6 +3847,100 @@ return nullptr; } +// Iterate over the load instructions of LoadCoercion map and it replaces them +// with the right sequence of instructions. Next, it checks if any other load in +// LoadCoercion map can be optimized with the newly generated instructions. +// Finally, it runs value numbering for the new instructions. In this way, any +// redundant instructions will be eliminated in the elimination phase. +bool NewGVN::implementLoadCoercion() { + bool AnythingReplaced = false; + for (const auto &P : LoadCoercion) { + LoadInst *LoadToOptimize = cast(P.first); + // The LoadCoercion map might have multiple load instructions that can be + // optimized with the same sequence of instructions. In this case, we + // process only the first load and we optimize the other loads with the + // sequence of instructions that we emitted for the first load. Here, we + // skip these loads in order not to process them again. + if (OptimizedLoads.count(LoadToOptimize)) + continue; + + Type *LoadToOptimizeTy = LoadToOptimize->getType(); + Value *NewValue = nullptr; + MemoryAccess *MA = P.second; + Instruction *DependingInsn = cast(MA)->getMemoryInst(); + BasicBlock *DependingInsnBB = cast(DependingInsn)->getParent(); + Instruction *InsnBeforeLoadToOptimize = LoadToOptimize->getPrevNode(); + Instruction *InsnBeforeTerminatorInDependingInsnBB = + DependingInsnBB->getTerminator()->getPrevNode(); + bool DefUSeAreInDifferentBB = + DependingInsnBB != LoadToOptimize->getParent(); + // If the load and the depending instruction are in different basic blocks, + // then the new sequence of instructions is emitted at the end of the basic + // block of the depending instruction. In this way, the newly generated + // instructions can be used by other loads that are in basic blocks that are + // dominated by the basic block of the depending instruction. If the load + // and the depending instruction are in the same basic block, then we emit + // them just before the load. + Instruction *InsertPtr = DefUSeAreInDifferentBB + ? DependingInsnBB->getTerminator() + : LoadToOptimize; + if (StoreInst *Store = dyn_cast(DependingInsn)) { + int Offset = analyzeLoadFromClobberingStore( + LoadToOptimizeTy, LoadToOptimize->getPointerOperand(), Store, DL); + // Emits the sequence of the instructions that replace the load. + NewValue = getStoreValueForLoad(Store->getValueOperand(), Offset, + LoadToOptimizeTy, InsertPtr, DL); + } + OptimizedLoads.insert(LoadToOptimize); + InstructionsToErase.insert(LoadToOptimize); + LoadToOptimize->replaceAllUsesWith(NewValue); + LLVM_DEBUG(dbgs() << "Load coersion: The load " << *LoadToOptimize + << " was eliminated and its uses were replaced by " + << *NewValue << "\n"); + + // Iterate the LoadCoercion map and check if there is any other load + // instruction that can be replaced with the same sequence of instructions. + for (const auto &P : LoadCoercion) { + LoadInst *LI = cast(P.first); + + if (LI == LoadToOptimize) + continue; + + // Check if the two load instructions have the same type and if the memory + // instructions that they depend on have the same memory access. + if (LoadToOptimize->getType() == LI->getType() && MA == P.second) { + OptimizedLoads.insert(LI); + InstructionsToErase.insert(LI); + LI->replaceAllUsesWith(NewValue); + LLVM_DEBUG(dbgs() << "Load coersion: The load " << *LI + << " was eliminated and its uses were replaced by " + << *NewValue << "\n"); + } + } + + // Collect the newly generated instructions and run value numbering for + // them. In this way, the new instructions will be inserted in the + // corresponding congruence classes. In case any of these instructions are + // redundant, they will be optimized away in the elimiantion phase. + Instruction *FirstNewlyGeneratedInsn = + DefUSeAreInDifferentBB + ? InsnBeforeTerminatorInDependingInsnBB->getNextNode() + : InsnBeforeLoadToOptimize->getNextNode(); + Instruction *LastNewlyGeneratedInsn = DefUSeAreInDifferentBB + ? DependingInsnBB->getTerminator() + : LoadToOptimize; + for (Instruction *CurInsn = FirstNewlyGeneratedInsn; + CurInsn != LastNewlyGeneratedInsn; CurInsn = CurInsn->getNextNode()) { + TOPClass->insert(CurInsn); + ValueToClass[CurInsn] = TOPClass; + valueNumberInstruction(CurInsn); + updateProcessedCount(CurInsn); + } + AnythingReplaced = true; + } + return AnythingReplaced; +} + bool NewGVN::eliminateInstructions(Function &F) { // This is a non-standard eliminator. The normal way to eliminate is // to walk the dominator tree in order, keeping track of available diff --git a/llvm/test/Transforms/NewGVN/load_coercion_between_store_and_load.ll b/llvm/test/Transforms/NewGVN/load_coercion_between_store_and_load.ll --- a/llvm/test/Transforms/NewGVN/load_coercion_between_store_and_load.ll +++ b/llvm/test/Transforms/NewGVN/load_coercion_between_store_and_load.ll @@ -1,12 +1,12 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -S -gvn < %s | FileCheck %s -check-prefix=GVN-CHECK +; RUN: opt -S -newgvn < %s | FileCheck %s -check-prefix=NEW-GVN-CHECK define float @test1(i32 %V1, i32* %P) { -; GVN-CHECK-LABEL: @test1( -; GVN-CHECK-NEXT: store i32 [[V1:%.*]], i32* [[P:%.*]], align 4 -; GVN-CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P]] to float* -; GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[V1]] to float -; GVN-CHECK-NEXT: ret float [[TMP1]] +; NEW-GVN-CHECK-LABEL: @test1( +; NEW-GVN-CHECK-NEXT: store i32 [[V1:%.*]], i32* [[P:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P]] to float* +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[V1]] to float +; NEW-GVN-CHECK-NEXT: ret float [[TMP1]] ; store i32 %V1, i32* %P %P1 = bitcast i32* %P to float* @@ -15,13 +15,13 @@ } define float @test2(i64* %V1, i64** %P1) { -; GVN-CHECK-LABEL: @test2( -; GVN-CHECK-NEXT: store i64* [[V1:%.*]], i64** [[P1:%.*]], align 8 -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i64** [[P1]] to float* -; GVN-CHECK-NEXT: [[TMP1:%.*]] = ptrtoint i64* [[V1]] to i64 -; GVN-CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32 -; GVN-CHECK-NEXT: [[TMP3:%.*]] = bitcast i32 [[TMP2]] to float -; GVN-CHECK-NEXT: ret float [[TMP3]] +; NEW-GVN-CHECK-LABEL: @test2( +; NEW-GVN-CHECK-NEXT: store i64* [[V1:%.*]], i64** [[P1:%.*]], align 8 +; NEW-GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i64** [[P1]] to float* +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = ptrtoint i64* [[V1]] to i64 +; NEW-GVN-CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32 +; NEW-GVN-CHECK-NEXT: [[TMP3:%.*]] = bitcast i32 [[TMP2]] to float +; NEW-GVN-CHECK-NEXT: ret float [[TMP3]] ; store i64* %V1, i64** %P1 %P2 = bitcast i64** %P1 to float* @@ -30,11 +30,11 @@ } define i8 @test3(i32 %V1, i32* %P1) { -; GVN-CHECK-LABEL: @test3( -; GVN-CHECK-NEXT: store i32 [[V1:%.*]], i32* [[P1:%.*]], align 4 -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P1]] to i8* -; GVN-CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[V1]] to i8 -; GVN-CHECK-NEXT: ret i8 [[TMP1]] +; NEW-GVN-CHECK-LABEL: @test3( +; NEW-GVN-CHECK-NEXT: store i32 [[V1:%.*]], i32* [[P1:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P1]] to i8* +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[V1]] to i8 +; NEW-GVN-CHECK-NEXT: ret i8 [[TMP1]] ; store i32 %V1, i32* %P1 %P2 = bitcast i32* %P1 to i8* @@ -43,12 +43,12 @@ } define float @test4(i64 %V1, i64* %P1) { -; GVN-CHECK-LABEL: @test4( -; GVN-CHECK-NEXT: store i64 [[V1:%.*]], i64* [[P1:%.*]], align 4 -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i64* [[P1]] to float* -; GVN-CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[V1]] to i32 -; GVN-CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[TMP1]] to float -; GVN-CHECK-NEXT: ret float [[TMP2]] +; NEW-GVN-CHECK-LABEL: @test4( +; NEW-GVN-CHECK-NEXT: store i64 [[V1:%.*]], i64* [[P1:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i64* [[P1]] to float* +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[V1]] to i32 +; NEW-GVN-CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[TMP1]] to float +; NEW-GVN-CHECK-NEXT: ret float [[TMP2]] ; store i64 %V1, i64* %P1 %P2 = bitcast i64* %P1 to float* @@ -57,12 +57,12 @@ } define i8 @test5(i32* %P, i8* %T) { -; GVN-CHECK-LABEL: @test5( -; GVN-CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[T:%.*]], align 1 -; GVN-CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P:%.*]] to i8* -; GVN-CHECK-NEXT: [[P2:%.*]] = getelementptr i8, i8* [[P1]], i32 2 -; GVN-CHECK-NEXT: store i8 [[V1]], i8* [[P2]], align 1 -; GVN-CHECK-NEXT: ret i8 [[V1]] +; NEW-GVN-CHECK-LABEL: @test5( +; NEW-GVN-CHECK-NEXT: [[V1:%.*]] = load i8, i8* [[T:%.*]], align 1 +; NEW-GVN-CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P:%.*]] to i8* +; NEW-GVN-CHECK-NEXT: [[P2:%.*]] = getelementptr i8, i8* [[P1]], i32 2 +; NEW-GVN-CHECK-NEXT: store i8 [[V1]], i8* [[P2]], align 1 +; NEW-GVN-CHECK-NEXT: ret i8 [[V1]] ; %V1 = load i8, i8* %T %P1 = bitcast i32* %P to i8* @@ -74,11 +74,11 @@ } define i8* @test6(i64 %V1, i64* %P1) { -; GVN-CHECK-LABEL: @test6( -; GVN-CHECK-NEXT: store i64 [[V1:%.*]], i64* [[P1:%.*]], align 4 -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i64* [[P1]] to i8** -; GVN-CHECK-NEXT: [[TMP1:%.*]] = inttoptr i64 [[V1]] to i8* -; GVN-CHECK-NEXT: ret i8* [[TMP1]] +; NEW-GVN-CHECK-LABEL: @test6( +; NEW-GVN-CHECK-NEXT: store i64 [[V1:%.*]], i64* [[P1:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i64* [[P1]] to i8** +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = inttoptr i64 [[V1]] to i8* +; NEW-GVN-CHECK-NEXT: ret i8* [[TMP1]] ; store i64 %V1, i64* %P1 %P2 = bitcast i64* %P1 to i8** @@ -87,12 +87,12 @@ } define i32 @test7(double %V1, double* %P1) { -; GVN-CHECK-LABEL: @test7( -; GVN-CHECK-NEXT: store double [[V1:%.*]], double* [[P1:%.*]], align 8 -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast double* [[P1]] to i32* -; GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[V1]] to i64 -; GVN-CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32 -; GVN-CHECK-NEXT: ret i32 [[TMP2]] +; NEW-GVN-CHECK-LABEL: @test7( +; NEW-GVN-CHECK-NEXT: store double [[V1:%.*]], double* [[P1:%.*]], align 8 +; NEW-GVN-CHECK-NEXT: [[P2:%.*]] = bitcast double* [[P1]] to i32* +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[V1]] to i64 +; NEW-GVN-CHECK-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32 +; NEW-GVN-CHECK-NEXT: ret i32 [[TMP2]] ; store double %V1, double* %P1 %P2 = bitcast double* %P1 to i32* @@ -101,13 +101,13 @@ } define i8 @test8(i32 %V1, i32* %P1) { -; GVN-CHECK-LABEL: @test8( -; GVN-CHECK-NEXT: store i32 [[V1:%.*]], i32* [[P1:%.*]], align 4 -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P1]] to i8* -; GVN-CHECK-NEXT: [[P3:%.*]] = getelementptr i8, i8* [[P2]], i32 2 -; GVN-CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[V1]], 16 -; GVN-CHECK-NEXT: [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8 -; GVN-CHECK-NEXT: ret i8 [[TMP2]] +; NEW-GVN-CHECK-LABEL: @test8( +; NEW-GVN-CHECK-NEXT: store i32 [[V1:%.*]], i32* [[P1:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P1]] to i8* +; NEW-GVN-CHECK-NEXT: [[P3:%.*]] = getelementptr i8, i8* [[P2]], i32 2 +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[V1]], 16 +; NEW-GVN-CHECK-NEXT: [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8 +; NEW-GVN-CHECK-NEXT: ret i8 [[TMP2]] ; store i32 %V1, i32* %P1 %P2 = bitcast i32* %P1 to i8* @@ -117,15 +117,14 @@ } define double @test9(i64 %V, i64* %P1, i1 %cond) { -; GVN-CHECK-LABEL: @test9( -; GVN-CHECK-NEXT: store i64 [[V:%.*]], i64* [[P1:%.*]], align 4 -; GVN-CHECK-NEXT: [[P3:%.*]] = bitcast i64* [[P1]] to double* -; GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[V]] to double -; GVN-CHECK-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]] -; GVN-CHECK: T: -; GVN-CHECK-NEXT: ret double [[TMP1]] -; GVN-CHECK: F: -; GVN-CHECK-NEXT: ret double [[TMP1]] +; NEW-GVN-CHECK-LABEL: @test9( +; NEW-GVN-CHECK-NEXT: store i64 [[V:%.*]], i64* [[P1:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[V]] to double +; NEW-GVN-CHECK-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]] +; NEW-GVN-CHECK: T: +; NEW-GVN-CHECK-NEXT: ret double [[TMP1]] +; NEW-GVN-CHECK: F: +; NEW-GVN-CHECK-NEXT: ret double [[TMP1]] ; %A = load i64 , i64* %P1 store i64 %V, i64* %P1 @@ -142,15 +141,15 @@ } define <{i8, float}> @test10(i32 %V0, i32* %P) { -; GVN-CHECK-LABEL: @test10( -; GVN-CHECK-NEXT: store i32 [[V0:%.*]], i32* [[P:%.*]], align 4 -; GVN-CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P]] to float* -; GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[V0]] to float -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P]] to i8* -; GVN-CHECK-NEXT: [[TMP2:%.*]] = trunc i32 [[V0]] to i8 -; GVN-CHECK-NEXT: [[I1:%.*]] = insertvalue <{ i8, float }> undef, i8 [[TMP2]], 0 -; GVN-CHECK-NEXT: [[I2:%.*]] = insertvalue <{ i8, float }> [[I1]], float [[TMP1]], 1 -; GVN-CHECK-NEXT: ret <{ i8, float }> [[I2]] +; NEW-GVN-CHECK-LABEL: @test10( +; NEW-GVN-CHECK-NEXT: store i32 [[V0:%.*]], i32* [[P:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P]] to float* +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[V0]] to float +; NEW-GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P]] to i8* +; NEW-GVN-CHECK-NEXT: [[TMP2:%.*]] = trunc i32 [[V0]] to i8 +; NEW-GVN-CHECK-NEXT: [[I1:%.*]] = insertvalue <{ i8, float }> undef, i8 [[TMP2]], 0 +; NEW-GVN-CHECK-NEXT: [[I2:%.*]] = insertvalue <{ i8, float }> [[I1]], float [[TMP1]], 1 +; NEW-GVN-CHECK-NEXT: ret <{ i8, float }> [[I2]] ; store i32 %V0, i32* %P %P1 = bitcast i32* %P to float* @@ -163,19 +162,19 @@ } define <{i8, float}> @test11(i32 %V0, i32* %P, i1 %cond) { -; GVN-CHECK-LABEL: @test11( -; GVN-CHECK-NEXT: store i32 [[V0:%.*]], i32* [[P:%.*]], align 4 -; GVN-CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[V0]] to i8 -; GVN-CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[V0]] to float -; GVN-CHECK-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]] -; GVN-CHECK: T: -; GVN-CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P]] to float* -; GVN-CHECK-NEXT: [[I1:%.*]] = insertvalue <{ i8, float }> undef, float [[TMP2]], 1 -; GVN-CHECK-NEXT: ret <{ i8, float }> [[I1]] -; GVN-CHECK: F: -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P]] to i8* -; GVN-CHECK-NEXT: [[I2:%.*]] = insertvalue <{ i8, float }> undef, i8 [[TMP1]], 0 -; GVN-CHECK-NEXT: ret <{ i8, float }> [[I2]] +; NEW-GVN-CHECK-LABEL: @test11( +; NEW-GVN-CHECK-NEXT: store i32 [[V0:%.*]], i32* [[P:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[V0]] to float +; NEW-GVN-CHECK-NEXT: [[TMP2:%.*]] = trunc i32 [[V0]] to i8 +; NEW-GVN-CHECK-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]] +; NEW-GVN-CHECK: T: +; NEW-GVN-CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P]] to float* +; NEW-GVN-CHECK-NEXT: [[I1:%.*]] = insertvalue <{ i8, float }> undef, float [[TMP1]], 1 +; NEW-GVN-CHECK-NEXT: ret <{ i8, float }> [[I1]] +; NEW-GVN-CHECK: F: +; NEW-GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P]] to i8* +; NEW-GVN-CHECK-NEXT: [[I2:%.*]] = insertvalue <{ i8, float }> undef, i8 [[TMP2]], 0 +; NEW-GVN-CHECK-NEXT: ret <{ i8, float }> [[I2]] ; store i32 %V0, i32* %P br i1 %cond, label %T, label %F @@ -194,18 +193,16 @@ } define <{float, float}> @test12(i32 %V0, i32* %P, i1 %cond) { -; GVN-CHECK-LABEL: @test12( -; GVN-CHECK-NEXT: store i32 [[V0:%.*]], i32* [[P:%.*]], align 4 -; GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[V0]] to float -; GVN-CHECK-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]] -; GVN-CHECK: T: -; GVN-CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P]] to float* -; GVN-CHECK-NEXT: [[I1:%.*]] = insertvalue <{ float, float }> undef, float [[TMP1]], 1 -; GVN-CHECK-NEXT: ret <{ float, float }> [[I1]] -; GVN-CHECK: F: -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P]] to float* -; GVN-CHECK-NEXT: [[I2:%.*]] = insertvalue <{ float, float }> undef, float [[TMP1]], 0 -; GVN-CHECK-NEXT: ret <{ float, float }> [[I2]] +; NEW-GVN-CHECK-LABEL: @test12( +; NEW-GVN-CHECK-NEXT: store i32 [[V0:%.*]], i32* [[P:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[V0]] to float +; NEW-GVN-CHECK-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]] +; NEW-GVN-CHECK: T: +; NEW-GVN-CHECK-NEXT: [[I1:%.*]] = insertvalue <{ float, float }> undef, float [[TMP1]], 1 +; NEW-GVN-CHECK-NEXT: ret <{ float, float }> [[I1]] +; NEW-GVN-CHECK: F: +; NEW-GVN-CHECK-NEXT: [[I2:%.*]] = insertvalue <{ float, float }> undef, float [[TMP1]], 0 +; NEW-GVN-CHECK-NEXT: ret <{ float, float }> [[I2]] ; store i32 %V0, i32* %P br i1 %cond, label %T, label %F @@ -224,13 +221,13 @@ } define i8 @test13(i32* %P1, i32 %V1) { -; GVN-CHECK-LABEL: @test13( -; GVN-CHECK-NEXT: store i32 [[V1:%.*]], i32* [[P1:%.*]], align 4 -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P1]] to i8* -; GVN-CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[V1]] to i8 -; GVN-CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[P1]] to i64* -; GVN-CHECK-NEXT: [[V5:%.*]] = add i8 [[TMP1]], [[TMP1]] -; GVN-CHECK-NEXT: ret i8 [[V5]] +; NEW-GVN-CHECK-LABEL: @test13( +; NEW-GVN-CHECK-NEXT: store i32 [[V1:%.*]], i32* [[P1:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P1]] to i8* +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[V1]] to i8 +; NEW-GVN-CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[P1]] to i64* +; NEW-GVN-CHECK-NEXT: [[V5:%.*]] = add i8 [[TMP1]], [[TMP1]] +; NEW-GVN-CHECK-NEXT: ret i8 [[V5]] ; store i32 %V1, i32* %P1 %P2 = bitcast i32* %P1 to i8* @@ -243,12 +240,11 @@ } define i8 @test14(i32* %P1, i32 %V1) { -; GVN-CHECK-LABEL: @test14( -; GVN-CHECK-NEXT: store i32 [[V1:%.*]], i32* [[P1:%.*]], align 4 -; GVN-CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P1]] to i8* -; GVN-CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[V1]] to i8 -; GVN-CHECK-NEXT: [[V5:%.*]] = add i8 [[TMP1]], [[TMP1]] -; GVN-CHECK-NEXT: ret i8 [[V5]] +; NEW-GVN-CHECK-LABEL: @test14( +; NEW-GVN-CHECK-NEXT: store i32 [[V1:%.*]], i32* [[P1:%.*]], align 4 +; NEW-GVN-CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[V1]] to i8 +; NEW-GVN-CHECK-NEXT: [[V5:%.*]] = add i8 [[TMP1]], [[TMP1]] +; NEW-GVN-CHECK-NEXT: ret i8 [[V5]] ; store i32 %V1, i32* %P1 %P2 = bitcast i32* %P1 to i8* diff --git a/llvm/test/Transforms/NewGVN/pr14166-xfail.ll b/llvm/test/Transforms/NewGVN/pr14166-xfail.ll --- a/llvm/test/Transforms/NewGVN/pr14166-xfail.ll +++ b/llvm/test/Transforms/NewGVN/pr14166-xfail.ll @@ -1,4 +1,3 @@ -; XFAIL: * ; RUN: opt -disable-basic-aa -passes=newgvn -S < %s | FileCheck %s ; NewGVN fails this due to missing load coercion target datalayout = "e-p:32:32:32"