Index: llvm/lib/Transforms/Scalar/LICM.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LICM.cpp +++ llvm/lib/Transforms/Scalar/LICM.cpp @@ -1804,6 +1804,8 @@ NewSI->setDebugLoc(DL); if (AATags) NewSI->setAAMetadata(AATags); + // FIXME: not sure if noalias_sidechannel propagation should be allowed + // here: dependend side channels should also migrate first ! if (MSSAU) { MemoryAccess *MSSAInsertPoint = MSSAInsertPts[i]; @@ -1957,7 +1959,9 @@ if (SomePtr->getType() != ASIV->getType()) return false; - for (User *U : ASIV->users()) { + for (auto U_it = ASIV->user_begin(), U_it_end = ASIV->user_end(); + U_it != U_it_end; ++U_it) { + User *U = *U_it; // Ignore instructions that are outside the loop. Instruction *UI = dyn_cast(U); if (!UI || !CurLoop->contains(UI)) @@ -1966,6 +1970,9 @@ // If there is an non-load/store instruction in the loop, we can't promote // it. if (LoadInst *Load = dyn_cast(UI)) { + if (U_it.getUse().getOperandNo() == + Load->getNoaliasSideChannelOperandIndex()) + continue; if (!Load->isUnordered()) return false; @@ -1988,6 +1995,10 @@ Alignment = std::max(Alignment, InstAlignment); } } else if (const StoreInst *Store = dyn_cast(UI)) { + if (U_it.getUse().getOperandNo() == + Store->getNoaliasSideChannelOperandIndex()) + continue; + // Stores *of* the pointer are not interesting, only stores *to* the // pointer. if (UI->getOperand(1) != ASIV) @@ -2036,8 +2047,18 @@ MaybeAlign(Store->getAlignment()), MDL, Preheader->getTerminator(), DT); } - } else - return false; // Not a load or store. + } else { + // Not a load or store. + if (IntrinsicInst *II = dyn_cast(UI)) { + if (II->getIntrinsicID() == Intrinsic::side_noalias || + II->getIntrinsicID() == Intrinsic::noalias_arg_guard || + II->getIntrinsicID() == Intrinsic::noalias_copy_guard) { + // those must not block promotion. + continue; + } + } + return false; + } // Merge the AA tags. if (LoopUses.empty()) { @@ -2123,6 +2144,8 @@ PreheaderLoad->setDebugLoc(DL); if (AATags) PreheaderLoad->setAAMetadata(AATags); + // FIXME: not sure if noalias_sidechannel propagation should be allowed + // here: dependend side channels should also migrate first ! SSA.AddAvailableValue(Preheader, PreheaderLoad); if (MSSAU) { Index: llvm/test/Transforms/LICM/noalias.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/LICM/noalias.ll @@ -0,0 +1,87 @@ +; RUN: opt -S -basicaa -licm -enable-mssa-loop-dependency=false %s | FileCheck -check-prefixes=CHECK,AST %s +; RUN: opt -S -basicaa -licm -enable-mssa-loop-dependency=true %s | FileCheck -check-prefixes=CHECK,MSSA %s +; RUN: opt -aa-pipeline=basic-aa -passes='require,require,require,require,loop(licm)' < %s -S | FileCheck -check-prefixes=CHECK,AST %s + + +; Function Attrs: nounwind +define dso_local void @test01(i32* %_p, i32 %n) #0 { +entry: + %0 = call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !2) + br label %do.body + +do.body: ; preds = %do.body, %entry + %n.addr.0 = phi i32 [ %n, %entry ], [ %dec, %do.body ] + %1 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_p, i8* %0, i32** null, i32** undef, i32 0, metadata !2), !tbaa !5, !noalias !2 + store i32 42, i32* %_p, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 + %dec = add nsw i32 %n.addr.0, -1 + %cmp = icmp ne i32 %dec, 0 + br i1 %cmp, label %do.body, label %do.end + +do.end: ; preds = %do.body + ret void +} + +; CHECK-LABEL: @test01( +; CHECK-LABEL: entry: +; CHECK: %0 = call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !2) +; CHECK: %1 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_p, i8* %0, i32** null, i32** undef, i32 0, metadata !2), !tbaa !5, !noalias !2 +; MSSA: store i32 42, i32* %_p, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 +; CHECK-LABEL: do.body: +; CHECK-LABEL: do.end: +; AST: store i32 42, i32* %_p, align 4, !tbaa !9 +; CHECK: ret void + +; Function Attrs: nounwind +define dso_local void @test02(i32* %_p, i32 %n) #0 { +entry: + br label %do.body + +do.body: ; preds = %do.body, %entry + %n.addr.0 = phi i32 [ %n, %entry ], [ %dec, %do.body ] + %0 = call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !11) + %1 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_p, i8* %0, i32** null, i32** undef, i32 0, metadata !11), !tbaa !5, !noalias !11 + store i32 42, i32* %_p, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !11 + %dec = add nsw i32 %n.addr.0, -1 + %cmp = icmp ne i32 %dec, 0 + br i1 %cmp, label %do.body, label %do.end + +do.end: ; preds = %do.body + ret void +} + +; CHECK-LABEL: @test02( +; CHECK-LABEL: entry: +; CHECK-LABEL: do.body: +; CHECK: %0 = call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !11) +; CHECK: %1 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_p, i8* %0, i32** null, i32** undef, i32 0, metadata !11), !tbaa !5, !noalias !11 +; CHECK-LABEL: do.end: +; CHECK: store i32 42, i32* %_p, align 4, !tbaa !9 +; CHECK: ret void + +; Function Attrs: argmemonly nounwind +declare i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32**, i32, metadata) #1 + +; Function Attrs: nounwind readnone speculatable +declare i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind readnone speculatable } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang"} +!2 = !{!3} +!3 = distinct !{!3, !4, !"test01: rp"} +!4 = distinct !{!4, !"test01"} +!5 = !{!6, !6, i64 0, i64 4} +!6 = !{!7, i64 4, !"any pointer"} +!7 = !{!8, i64 1, !"omnipotent char"} +!8 = !{!"Simple C/C++ TBAA"} +!9 = !{!10, !10, i64 0, i64 4} +!10 = !{!7, i64 4, !"int"} +!11 = !{!12} +!12 = distinct !{!12, !13, !"test02: rp"} +!13 = distinct !{!13, !"test02"}