Files
llvm-project/polly/lib/Transform/ScopInliner.cpp
Michael Kruse 458f1aae8d [Polly] Forward VFS from PassBuilder for IO sandboxing (#188657)
#184545 default-enables the IO sandbox in assert-builds. This causes
Clang using Polly to crash (#188568).

The issue is that `PassBuilder` uses `vfs::getRealFileSystem()` by
default which is considered a IO sandbox violation in the Clang process.
With this PR store the VFS from the `PassBuilder` from the original
`registerPollyPasses` call for creating other `PassBuilder` instances.

This PR also adds infrastructure for running Polly in `clang` (in
addition in `opt`). `opt` does not enable the sandbox such that we need
separate tests using Clang.

Closes: #188568
2026-03-28 23:55:05 +01:00

126 lines
4.4 KiB
C++

//===---- ScopInliner.cpp - Polyhedral based inliner ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Take a SCC and:
// 1. If it has more than one component, bail out (contains cycles)
// 2. If it has just one component, and if the function is entirely a scop,
// inline it.
//
//===----------------------------------------------------------------------===//
#include "polly/ScopInliner.h"
#include "polly/ScopDetection.h"
#include "polly/ScopInliner.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "polly/Support/PollyDebug.h"
#define DEBUG_TYPE "polly-scop-inliner"
using namespace llvm;
using namespace polly;
namespace {
/// Inliner implementation that works with both, LPM (using SCC_t=CallGraph) and
/// NPM (using SCC_t=LazyCallGraph::SCC)
template <typename SCC_t>
bool runScopInlinerImpl(Function *F, SCC_t &SCC,
IntrusiveRefCntPtr<vfs::FileSystem> FS) {
// We do not try to inline non-trivial SCCs because this would lead to
// "infinite" inlining if we are not careful.
if (SCC.size() > 1)
return false;
assert(SCC.size() == 1 && "found empty SCC");
// If the function is a nullptr, or the function is a declaration.
if (!F)
return false;
if (F->isDeclaration()) {
POLLY_DEBUG(dbgs() << "Skipping " << F->getName()
<< "because it is a declaration.\n");
return false;
}
PassBuilder PB(
/*TM=*/nullptr,
/*PipelineTuningOptions=*/{},
/*PGOOpt=*/{},
/*PIC=*/nullptr, std::move(FS));
// Populate analysis managers and register Polly-specific analyses.
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
PB.registerModuleAnalyses(MAM);
PB.registerCGSCCAnalyses(CGAM);
PB.registerFunctionAnalyses(FAM);
PB.registerLoopAnalyses(LAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
auto &DT = FAM.getResult<DominatorTreeAnalysis>(*F);
auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(*F);
auto &LI = FAM.getResult<LoopAnalysis>(*F);
auto &RI = FAM.getResult<RegionInfoAnalysis>(*F);
auto &AA = FAM.getResult<AAManager>(*F);
auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
ScopDetection SD(DT, SE, LI, RI, AA, ORE);
SD.detect(*F);
const bool HasScopAsTopLevelRegion =
SD.ValidRegions.contains(RI.getTopLevelRegion());
bool Changed = false;
if (HasScopAsTopLevelRegion) {
POLLY_DEBUG(dbgs() << "Skipping " << F->getName()
<< " has scop as top level region");
F->addFnAttr(llvm::Attribute::AlwaysInline);
ModulePassManager MPM;
MPM.addPass(AlwaysInlinerPass());
Module *M = F->getParent();
assert(M && "Function has illegal module");
PreservedAnalyses PA = MPM.run(*M, MAM);
if (!PA.areAllPreserved())
Changed = true;
} else {
POLLY_DEBUG(dbgs() << F->getName()
<< " does NOT have scop as top level region\n");
}
return Changed;
}
} // namespace
polly::ScopInlinerPass::ScopInlinerPass(IntrusiveRefCntPtr<vfs::FileSystem> FS)
: FS(std::move(FS)) {
if (!polly::PollyAllowFullFunction) {
report_fatal_error(
"Aborting from ScopInliner because it only makes sense to run with "
"-polly-allow-full-function. "
"The heurtistic for ScopInliner checks that the full function is a "
"Scop, which happens if and only if polly-allow-full-function is "
" enabled. "
" If not, the entry block is not included in the Scop");
}
}
PreservedAnalyses polly::ScopInlinerPass::run(llvm::LazyCallGraph::SCC &SCC,
llvm::CGSCCAnalysisManager &AM,
llvm::LazyCallGraph &CG,
llvm::CGSCCUpdateResult &UR) {
Function *F = &SCC.begin()->getFunction();
bool Changed = runScopInlinerImpl(F, SCC, FS);
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
}