[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
This commit is contained in:
@@ -29,7 +29,7 @@ with worker.run(
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DCMAKE_C_COMPILER_LAUNCHER=ccache",
|
||||
"-DCMAKE_CXX_COMPILER_LAUNCHER=ccache",
|
||||
"-DLLVM_ENABLE_PROJECTS=polly",
|
||||
"-DLLVM_ENABLE_PROJECTS=polly;clang",
|
||||
"-DLLVM_TARGETS_TO_BUILD=X86",
|
||||
"-DLLVM_ENABLE_LLD=ON",
|
||||
"-DLLVM_ENABLE_ASSERTIONS=ON",
|
||||
|
||||
@@ -30,7 +30,7 @@ with worker.run(
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DCMAKE_C_COMPILER_LAUNCHER=ccache",
|
||||
"-DCMAKE_CXX_COMPILER_LAUNCHER=ccache",
|
||||
"-DLLVM_ENABLE_PROJECTS=polly",
|
||||
"-DLLVM_ENABLE_PROJECTS=polly;clang",
|
||||
"-DLLVM_TARGETS_TO_BUILD=X86",
|
||||
"-DLLVM_ENABLE_LLD=ON",
|
||||
"-DLLVM_ENABLE_ASSERTIONS=ON",
|
||||
|
||||
@@ -9,14 +9,23 @@
|
||||
#ifndef POLLY_POLLYINLINER_H
|
||||
#define POLLY_POLLYINLINER_H
|
||||
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/Analysis/CGSCCPassManager.h"
|
||||
#include "llvm/Analysis/LazyCallGraph.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace vfs {
|
||||
class FileSystem;
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
namespace polly {
|
||||
class ScopInlinerPass : public llvm::PassInfoMixin<ScopInlinerPass> {
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
|
||||
|
||||
public:
|
||||
ScopInlinerPass();
|
||||
explicit ScopInlinerPass(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS);
|
||||
|
||||
llvm::PreservedAnalyses run(llvm::LazyCallGraph::SCC &C,
|
||||
llvm::CGSCCAnalysisManager &AM,
|
||||
|
||||
@@ -8,7 +8,7 @@ MODULE_PASS("polly-custom", createModuleToFunctionPassAdaptor(PollyFunctionPass(
|
||||
#ifndef CGSCC_PASS
|
||||
#define CGSCC_PASS(NAME, CREATE_PASS, PARSER)
|
||||
#endif
|
||||
CGSCC_PASS("polly-inline", ScopInlinerPass(), parseNoOptions)
|
||||
CGSCC_PASS("polly-inline", ScopInlinerPass(FS), parseNoOptions)
|
||||
#undef CGSCC_PASS
|
||||
|
||||
#ifndef FUNCTION_PASS
|
||||
|
||||
@@ -459,8 +459,13 @@ parsePollyCustomOptions(StringRef Params) {
|
||||
/// The IR may still be modified.
|
||||
static void buildCommonPollyPipeline(FunctionPassManager &PM,
|
||||
OptimizationLevel Level,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> FS,
|
||||
bool EnableForOpt) {
|
||||
PassBuilder PB;
|
||||
PassBuilder PB(
|
||||
/*TM=*/nullptr,
|
||||
/*PipelineTuningOptions=*/{},
|
||||
/*PGOOpt=*/{},
|
||||
/*PIC=*/nullptr, std::move(FS));
|
||||
|
||||
ExitOnError Err("Inconsistent Polly configuration: ");
|
||||
PollyPassOptions &&Opts =
|
||||
@@ -475,7 +480,8 @@ static void buildCommonPollyPipeline(FunctionPassManager &PM,
|
||||
}
|
||||
|
||||
static void buildEarlyPollyPipeline(llvm::ModulePassManager &MPM,
|
||||
llvm::OptimizationLevel Level) {
|
||||
llvm::OptimizationLevel Level,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> FS) {
|
||||
bool EnableForOpt =
|
||||
shouldEnablePollyForOptimization() && Level.isOptimizingForSpeed();
|
||||
if (!shouldEnablePollyForDiagnostic() && !EnableForOpt)
|
||||
@@ -494,7 +500,7 @@ static void buildEarlyPollyPipeline(llvm::ModulePassManager &MPM,
|
||||
FPM = FunctionPassManager();
|
||||
}
|
||||
|
||||
buildCommonPollyPipeline(FPM, Level, EnableForOpt);
|
||||
buildCommonPollyPipeline(FPM, Level, std::move(FS), EnableForOpt);
|
||||
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
|
||||
|
||||
if (DumpAfter)
|
||||
@@ -504,7 +510,8 @@ static void buildEarlyPollyPipeline(llvm::ModulePassManager &MPM,
|
||||
}
|
||||
|
||||
static void buildLatePollyPipeline(FunctionPassManager &PM,
|
||||
llvm::OptimizationLevel Level) {
|
||||
llvm::OptimizationLevel Level,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> FS) {
|
||||
bool EnableForOpt =
|
||||
shouldEnablePollyForOptimization() && Level.isOptimizingForSpeed();
|
||||
if (!shouldEnablePollyForDiagnostic() && !EnableForOpt)
|
||||
@@ -518,7 +525,7 @@ static void buildLatePollyPipeline(FunctionPassManager &PM,
|
||||
"not supported with NPM",
|
||||
false);
|
||||
|
||||
buildCommonPollyPipeline(PM, Level, EnableForOpt);
|
||||
buildCommonPollyPipeline(PM, Level, std::move(FS), EnableForOpt);
|
||||
|
||||
if (DumpAfter)
|
||||
PM.addPass(DumpFunctionPass("-after"));
|
||||
@@ -542,7 +549,8 @@ static llvm::Expected<std::monostate> parseNoOptions(StringRef Params) {
|
||||
static llvm::Expected<bool>
|
||||
parseCGPipeline(StringRef Name, llvm::CGSCCPassManager &CGPM,
|
||||
PassInstrumentationCallbacks *PIC,
|
||||
ArrayRef<PassBuilder::PipelineElement> Pipeline) {
|
||||
ArrayRef<PassBuilder::PipelineElement> Pipeline,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> FS) {
|
||||
#define CGSCC_PASS(NAME, CREATE_PASS, PARSER) \
|
||||
if (PassBuilder::checkParametrizedPassName(Name, NAME)) { \
|
||||
auto Params = PassBuilder::parsePassParameters(PARSER, Name, NAME); \
|
||||
@@ -624,6 +632,7 @@ parseModulePipeline(StringRef Name, llvm::ModulePassManager &MPM,
|
||||
/// handle LICMed code to make it useful.
|
||||
void registerPollyPasses(PassBuilder &PB) {
|
||||
PassInstrumentationCallbacks *PIC = PB.getPassInstrumentationCallbacks();
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> FS = PB.getVirtualFileSystemPtr();
|
||||
|
||||
#define MODULE_PASS(NAME, CREATE_PASS, PARSER) \
|
||||
{ \
|
||||
@@ -652,10 +661,10 @@ void registerPollyPasses(PassBuilder &PB) {
|
||||
return Err(parseFunctionPipeline(Name, FPM, PIC, Pipeline));
|
||||
});
|
||||
PB.registerPipelineParsingCallback(
|
||||
[PIC](StringRef Name, CGSCCPassManager &CGPM,
|
||||
[PIC, FS](StringRef Name, CGSCCPassManager &CGPM,
|
||||
ArrayRef<PassBuilder::PipelineElement> Pipeline) -> bool {
|
||||
ExitOnError Err("Unable to parse Polly call graph pass: ");
|
||||
return Err(parseCGPipeline(Name, CGPM, PIC, Pipeline));
|
||||
return Err(parseCGPipeline(Name, CGPM, PIC, Pipeline, FS));
|
||||
});
|
||||
PB.registerPipelineParsingCallback(
|
||||
[PIC](StringRef Name, ModulePassManager &MPM,
|
||||
@@ -666,10 +675,16 @@ void registerPollyPasses(PassBuilder &PB) {
|
||||
|
||||
switch (PassPosition) {
|
||||
case POSITION_EARLY:
|
||||
PB.registerPipelineStartEPCallback(buildEarlyPollyPipeline);
|
||||
PB.registerPipelineStartEPCallback(
|
||||
[FS](ModulePassManager &MPM, OptimizationLevel Level) {
|
||||
buildEarlyPollyPipeline(MPM, Level, FS);
|
||||
});
|
||||
break;
|
||||
case POSITION_BEFORE_VECTORIZER:
|
||||
PB.registerVectorizerStartEPCallback(buildLatePollyPipeline);
|
||||
PB.registerVectorizerStartEPCallback(
|
||||
[FS](FunctionPassManager &FPM, OptimizationLevel Level) {
|
||||
buildLatePollyPipeline(FPM, Level, FS);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@ 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) {
|
||||
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)
|
||||
@@ -50,7 +52,11 @@ template <typename SCC_t> bool runScopInlinerImpl(Function *F, SCC_t &SCC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PassBuilder PB;
|
||||
PassBuilder PB(
|
||||
/*TM=*/nullptr,
|
||||
/*PipelineTuningOptions=*/{},
|
||||
/*PGOOpt=*/{},
|
||||
/*PIC=*/nullptr, std::move(FS));
|
||||
// Populate analysis managers and register Polly-specific analyses.
|
||||
LoopAnalysisManager LAM;
|
||||
FunctionAnalysisManager FAM;
|
||||
@@ -96,7 +102,8 @@ template <typename SCC_t> bool runScopInlinerImpl(Function *F, SCC_t &SCC) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
polly::ScopInlinerPass::ScopInlinerPass() {
|
||||
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 "
|
||||
@@ -113,6 +120,6 @@ PreservedAnalyses polly::ScopInlinerPass::run(llvm::LazyCallGraph::SCC &SCC,
|
||||
llvm::LazyCallGraph &CG,
|
||||
llvm::CGSCCUpdateResult &UR) {
|
||||
Function *F = &SCC.begin()->getFunction();
|
||||
bool Changed = runScopInlinerImpl(F, SCC);
|
||||
bool Changed = runScopInlinerImpl(F, SCC, FS);
|
||||
return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
1
polly/test/.clang-format
Normal file
1
polly/test/.clang-format
Normal file
@@ -0,0 +1 @@
|
||||
ColumnLimit: 0
|
||||
@@ -3,6 +3,7 @@ set(LLVM_SHLIBEXT "${CMAKE_SHARED_MODULE_SUFFIX}")
|
||||
add_custom_target(check-polly)
|
||||
set_target_properties(check-polly PROPERTIES FOLDER "Polly/Meta")
|
||||
|
||||
set(POLLY_TEST_C_COMPILER "")
|
||||
if(NOT LLVM_MAIN_SRC_DIR)
|
||||
find_program(LLVM_OPT NAMES opt HINTS ${LLVM_TOOLS_BINARY_DIR})
|
||||
find_program(LLVM_FILECHECK NAMES FileCheck HINTS ${LLVM_TOOLS_BINARY_DIR})
|
||||
@@ -35,6 +36,11 @@ else ()
|
||||
set(LLVM_NOT "${LLVM_TOOLS_BINARY_DIR}/not")
|
||||
set(POLLY_TEST_EXTRA_PATHS "")
|
||||
set(POLLY_TEST_DEPS llvm-config opt LLVMPolly FileCheck not count)
|
||||
|
||||
if (TARGET clang)
|
||||
set(POLLY_TEST_C_COMPILER "${LLVM_TOOLS_BINARY_DIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
list(APPEND POLLY_TEST_DEPS clang)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (POLLY_BUNDLED_ISL)
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#define N 10
|
||||
void foo(float A[restrict], double B[restrict], char C[restrict],
|
||||
int D[restrict], long E[restrict]) {
|
||||
for (long i = 0; i < N; i++)
|
||||
A[i] += B[i] + C[i] + D[i] + E[i];
|
||||
}
|
||||
|
||||
int main() {
|
||||
float A[N];
|
||||
double B[N];
|
||||
char C[N];
|
||||
int D[N];
|
||||
long E[N];
|
||||
|
||||
for (long i = 0; i < N; i++) {
|
||||
__sync_synchronize();
|
||||
A[i] = B[i] = C[i] = D[i] = E[i] = 42;
|
||||
}
|
||||
|
||||
foo(A, B, C, D, E);
|
||||
|
||||
return A[8];
|
||||
}
|
||||
@@ -4,11 +4,13 @@ import os
|
||||
import platform
|
||||
import re
|
||||
import subprocess
|
||||
import shlex
|
||||
|
||||
import lit.formats
|
||||
import lit.util
|
||||
|
||||
from lit.llvm import llvm_config
|
||||
from lit.llvm.subst import ToolSubst
|
||||
|
||||
# Configuration file for the 'lit' test runner.
|
||||
|
||||
@@ -55,6 +57,25 @@ llvm_config.use_default_substitutions()
|
||||
tool_patterns = ['opt', 'polly-isl-test']
|
||||
llvm_config.add_tool_substitutions(tool_patterns)
|
||||
|
||||
|
||||
if config.polly_test_c_compiler:
|
||||
config.suffixes += ['.c']
|
||||
llvm_polly_link_into_tools = lit.util.pythonize_bool(config.llvm_polly_link_into_tools)
|
||||
clang_args = []
|
||||
if not llvm_polly_link_into_tools:
|
||||
clang_args += [f'-fpass-plugin={config.polly_lib_dir}/LLVMPolly{config.llvm_shlibext}']
|
||||
llvm_config.add_tool_substitutions([
|
||||
ToolSubst("%clang",
|
||||
command = config.polly_test_c_compiler,
|
||||
extra_args = clang_args,
|
||||
unresolved = "fatal"
|
||||
)
|
||||
])
|
||||
lit_config.note(f"Using Clang: {config.polly_test_c_compiler} {shlex.join(clang_args)}")
|
||||
else:
|
||||
lit_config.note("Clang tests disabled: No compatible Clang found")
|
||||
|
||||
|
||||
# opt knows whether it is compiled with -DNDEBUG.
|
||||
import subprocess
|
||||
try:
|
||||
|
||||
@@ -4,12 +4,14 @@ config.llvm_src_root = "@LLVM_SOURCE_DIR@"
|
||||
config.llvm_obj_root = "@LLVM_BINARY_DIR@"
|
||||
config.llvm_tools_dir = lit_config.substitute("@LLVM_TOOLS_DIR@")
|
||||
config.llvm_libs_dir = lit_config.substitute("@LLVM_LIBS_DIR@")
|
||||
config.llvm_shlibext = "@LLVM_SHLIBEXT@"
|
||||
config.polly_obj_root = "@POLLY_BINARY_DIR@"
|
||||
config.polly_lib_dir = "@POLLY_LIB_DIR@"
|
||||
config.target_triple = "@LLVM_TARGET_TRIPLE@"
|
||||
config.llvm_polly_link_into_tools = "@LLVM_POLLY_LINK_INTO_TOOLS@"
|
||||
config.targets_to_build = "@TARGETS_TO_BUILD@"
|
||||
config.extra_paths = "@POLLY_TEST_EXTRA_PATHS@".split(";")
|
||||
config.polly_test_c_compiler = "@POLLY_TEST_C_COMPILER@"
|
||||
|
||||
## Check the current platform with regex
|
||||
import re
|
||||
|
||||
9
polly/test/polly.c
Normal file
9
polly/test/polly.c
Normal file
@@ -0,0 +1,9 @@
|
||||
// Sanity test for Polly in Clang
|
||||
// RUN: %clang %s -O2 -c -mllvm -polly -mllvm -polly-process-unprofitable -mllvm -print-pipeline-passes -o %t.o | FileCheck %s
|
||||
|
||||
// CHECK: ,polly,
|
||||
|
||||
void foo(int *A, int *B, int n) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
A[i] += B[i];
|
||||
}
|
||||
Reference in New Issue
Block a user