Index: lib/Transform/ScopInliner.cpp =================================================================== --- lib/Transform/ScopInliner.cpp +++ lib/Transform/ScopInliner.cpp @@ -59,8 +59,13 @@ // If the function is a nullptr, or the function is a declaration. if (!F) return false; + + // HACK: remove this before upstreaming + if (F->getName().count("__radiation_rg_MOD_coe") == 0 && + F->getName().count("__radiation_rg_MOD_inv") == 0) return false; + if (F->isDeclaration()) { - DEBUG(dbgs() << "Skipping " << F->getName() + DEBUG(dbgs() << "SKIPPING " << F->getName() << "because it is a declaration.\n"); return false; } @@ -73,16 +78,36 @@ RegionInfo &RI = FAM.getResult(*F); ScopDetection &SD = FAM.getResult(*F); - const bool HasScopAsTopLevelRegion = - SD.ValidRegions.count(RI.getTopLevelRegion()) > 0; + const auto TopLevelRegion = RI.getTopLevelRegion(); + + // Whether the entire function can be modeled as a Scop. + const bool IsFullyModeledAsScop = + SD.ValidRegions.count(TopLevelRegion) > 0; + + // Whether the function has a Scop that is a *unique* child of the top-level + // region. + const bool IsModeledByTopLevelChild = [&] { + // If toplevel has more than 1 child, bail out. + if (std::distance(TopLevelRegion->begin(), TopLevelRegion->end()) > 1) + return false; - if (HasScopAsTopLevelRegion) { - DEBUG(dbgs() << "Skipping " << F->getName() - << " has scop as top level region"); + for (auto ScopRegion : SD.ValidRegions) { + if (ScopRegion->getParent() == TopLevelRegion) { + return true; + } + } + return false; + }(); + + if (IsFullyModeledAsScop || IsModeledByTopLevelChild) { + FAM.clear(*F); + + DEBUG(dbgs() << "@ " << F->getName() << " DOES have scop as top level region.\n"); F->addFnAttr(llvm::Attribute::AlwaysInline); ModuleAnalysisManager MAM; PB.registerModuleAnalyses(MAM); + ModulePassManager MPM; MPM.addPass(AlwaysInlinerPass()); Module *M = F->getParent(); @@ -90,7 +115,7 @@ MPM.run(*M, MAM); } else { DEBUG(dbgs() << F->getName() - << " does NOT have scop as top level region\n"); + << " does NOT have scop as top level region.\n"); } return false; Index: test/ScopInliner/scop-from-entry-successor.ll =================================================================== --- /dev/null +++ test/ScopInliner/scop-from-entry-successor.ll @@ -0,0 +1,66 @@ +; RUN: opt %loadPolly -polly-detect-full-functions -polly-scop-inliner \ +; RUN: -polly-scops -analyze < %s | FileCheck %s + +; Check that we get the 2 nested loops by inlining `to_be_inlined` into +; `inline_site`, when the `to_be_inlined` has a `Scop` from the *successor* of +; the entry block to the exit node. + +; CHECK: Max Loop Depth: 2 + +; static const int N = 1000; +; +; void to_be_inlined(int A[]) { +; int B; // we do not allow dead code elimination on purpose to have an alloca. +; for(int i = 0; i < N; i++) +; A[i] *= 10; +; } +; +; void inline_site(int A[]) { +; for(int i = 0; i < N; i++) +; to_be_inlined(A); +; } + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.12.0" + + +define void @to_be_inlined(i32* %A) { +entry: + %alloc_to_block_modelling = alloca i32 + br label %entry.split + +entry.split: ; preds = %entry + br label %for.body + +for.body: ; preds = %entry.split, %for.body + %indvars.iv1 = phi i64 [ 0, %entry.split ], [ %indvars.iv.next, %for.body ] + %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv1 + %tmp = load i32, i32* %arrayidx, align 4 + %mul = mul nsw i32 %tmp, 10 + store i32 %mul, i32* %arrayidx, align 4 + %indvars.iv.next = add nuw nsw i64 %indvars.iv1, 1 + %exitcond = icmp eq i64 %indvars.iv.next, 1000 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} + +define void @inline_site(i32* %A) { +entry: + br label %entry.split + +entry.split: ; preds = %entry + br label %for.body + +for.body: ; preds = %entry.split, %for.body + %i.01 = phi i32 [ 0, %entry.split ], [ %inc, %for.body ] + tail call void @to_be_inlined(i32* %A) + %inc = add nuw nsw i32 %i.01, 1 + %exitcond = icmp eq i32 %inc, 1000 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} +