Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DAE][SYCL] Emit MD instead of updating integration header #2258

Merged
merged 4 commits into from
Aug 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ LANGOPT(SYCLUnnamedLambda , 1, 0, "Allow unnamed lambda SYCL kernels")
LANGOPT(SYCLVersion , 32, 0, "Version of the SYCL standard used")
LANGOPT(DeclareSPIRVBuiltins, 1, 0, "Declare SPIR-V builtin functions")
LANGOPT(SYCLExplicitSIMD , 1, 0, "SYCL compilation with explicit SIMD extension")
LANGOPT(EnableDAEInSpirKernels , 1, 0, "Enable Dead Argument Elimination in SPIR kernels")

LANGOPT(HIPUseNewLaunchAPI, 1, 0, "Use new kernel launching API for HIP")

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4455,6 +4455,8 @@ def fsycl_std_layout_kernel_params: Flag<["-"], "fsycl-std-layout-kernel-params"
def fsycl_allow_func_ptr : Flag<["-"], "fsycl-allow-func-ptr">,
HelpText<"Allow function pointers in SYCL device.">;
def fno_sycl_allow_func_ptr : Flag<["-"], "fno-sycl-allow-func-ptr">;
def fenable_sycl_dae : Flag<["-"], "fenable-sycl-dae">,
HelpText<"Enable Dead Argument Elimination in SPIR kernels">;

} // let Flags = [CC1Option]

Expand Down
9 changes: 9 additions & 0 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,15 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
if (LangOpts.SYCLIsDevice && CodeGenOpts.DisableLLVMPasses)
PerModulePasses.add(createDeadCodeEliminationPass());

// Eliminate dead arguments from SPIR kernels in SYCL environment.
// 1. Run DAE when LLVM optimizations are applied as well.
// 2. We cannot run DAE for ESIMD since the pointers to SPIR kernel
// functions are saved in !genx.kernels metadata.
// 3. DAE pass temporary guarded under option.
if (LangOpts.SYCLIsDevice && !CodeGenOpts.DisableLLVMPasses &&
!LangOpts.SYCLExplicitSIMD && LangOpts.EnableDAEInSpirKernels)
PerModulePasses.add(createDeadArgEliminationSYCLPass());

if (LangOpts.SYCLIsDevice && LangOpts.SYCLExplicitSIMD)
PerModulePasses.add(createGenXSPIRVWriterAdaptorPass());

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2596,6 +2596,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
}
}
Opts.SYCLExplicitSIMD = Args.hasArg(options::OPT_fsycl_esimd);
Opts.EnableDAEInSpirKernels = Args.hasArg(options::OPT_fenable_sycl_dae);
}

Opts.IncludeDefaultHeader = Args.hasArg(OPT_finclude_default_header);
Expand Down
96 changes: 11 additions & 85 deletions llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO.h"
Expand All @@ -55,11 +54,6 @@ using namespace llvm;

#define DEBUG_TYPE "deadargelim"

static cl::opt<std::string>
IntegrationHeaderFileName("integr-header-file",
cl::desc("Path to integration header file"),
cl::value_desc("filename"), cl::Hidden);

STATISTIC(NumArgumentsEliminated, "Number of unread args removed");
STATISTIC(NumRetValsEliminated , "Number of unused return values removed");
STATISTIC(NumArgumentsReplacedWithUndef,
Expand Down Expand Up @@ -760,78 +754,6 @@ void DeadArgumentEliminationPass::PropagateLiveness(const RetOrArg &RA) {
Uses.erase(Begin, I);
}

// Update kernel arguments table inside the integration header.
// For example:
// static constexpr const bool param_omit_table[] = {
// // OMIT_TABLE_BEGIN
// // kernel_name_1
// false, false, // <= update to true if the argument is dead
// // kernel_name_2
// false, false,
// // OMIT_TABLE_END
// };
// TODO: batch changes to multiple SPIR kernels and do one bulk update.
constexpr StringLiteral OMIT_TABLE_BEGIN("// OMIT_TABLE_BEGIN");
constexpr StringLiteral OMIT_TABLE_END("// OMIT_TABLE_END");
static void updateIntegrationHeader(StringRef SpirKernelName,
const ArrayRef<bool> &ArgAlive) {
ErrorOr<std::unique_ptr<MemoryBuffer>> IntHeaderBuffer =
MemoryBuffer::getFile(IntegrationHeaderFileName);

if (!IntHeaderBuffer)
report_fatal_error("unable to read integration header file '" +
IntegrationHeaderFileName +
"': " + IntHeaderBuffer.getError().message());

// 1. Find the region between OMIT_TABLE_BEGIN and OMIT_TABLE_END
StringRef IntHeader((*IntHeaderBuffer)->getBuffer());
if (!IntHeader.contains(OMIT_TABLE_BEGIN))
report_fatal_error(OMIT_TABLE_BEGIN +
" marker not found in integration header");
if (!IntHeader.contains(OMIT_TABLE_END))
report_fatal_error(OMIT_TABLE_END +
" marker not found in integration header");

size_t BeginRegionPos =
IntHeader.find(OMIT_TABLE_BEGIN) + OMIT_TABLE_BEGIN.size();
size_t EndRegionPos = IntHeader.find(OMIT_TABLE_END);

StringRef OmitArgTable = IntHeader.slice(BeginRegionPos, EndRegionPos);

// 2. Find the line that corresponds to the SPIR kernel
if (!OmitArgTable.contains(SpirKernelName))
report_fatal_error(
"Argument table not found in integration header for function '" +
SpirKernelName + "'");

size_t BeginLinePos =
OmitArgTable.find(SpirKernelName) + SpirKernelName.size();
size_t EndLinePos = OmitArgTable.find("//", BeginLinePos);

StringRef OmitArgLine = OmitArgTable.slice(BeginLinePos, EndLinePos);

size_t LineLeftTrim = OmitArgLine.size() - OmitArgLine.ltrim().size();
size_t LineRightTrim = OmitArgLine.size() - OmitArgLine.rtrim().size();

// 3. Construct new file contents and replace only that string.
std::string NewIntHeader;
NewIntHeader +=
IntHeader.take_front(BeginRegionPos + BeginLinePos + LineLeftTrim);
for (auto &AliveArg : ArgAlive)
NewIntHeader += AliveArg ? "false, " : "true, ";
NewIntHeader += IntHeader.drop_front(BeginRegionPos + BeginLinePos +
OmitArgLine.size() - LineRightTrim);

// 4. Flush the string into the file.
std::error_code EC;
raw_fd_ostream File(IntegrationHeaderFileName, EC, sys::fs::F_Text);

if (EC)
report_fatal_error("Cannot open integration header for writing.");

File << NewIntHeader;
}

// RemoveDeadStuffFromFunction - Remove any arguments and return values from F
// that are not in LiveValues. Transform the function and all of the callees of
// the function to not have these arguments and return values.
Expand Down Expand Up @@ -875,8 +797,17 @@ bool DeadArgumentEliminationPass::RemoveDeadStuffFromFunction(Function *F) {
}
}

if (CheckSpirKernels)
updateIntegrationHeader(F->getName(), ArgAlive);
if (CheckSpirKernels) {
SmallVector<Metadata *, 10> MDOmitArgs;
auto MDOmitArgTrue = llvm::ConstantAsMetadata::get(
ConstantInt::get(Type::getInt1Ty(F->getContext()), 1));
auto MDOmitArgFalse = llvm::ConstantAsMetadata::get(
ConstantInt::get(Type::getInt1Ty(F->getContext()), 0));
for (auto &AliveArg : ArgAlive)
MDOmitArgs.push_back(AliveArg ? MDOmitArgFalse : MDOmitArgTrue);
F->setMetadata("spir_kernel_omit_args",
llvm::MDNode::get(F->getContext(), MDOmitArgs));
}

// Find out the new return value.
Type *RetTy = FTy->getReturnType();
Expand Down Expand Up @@ -1193,11 +1124,6 @@ bool DeadArgumentEliminationPass::RemoveDeadStuffFromFunction(Function *F) {

PreservedAnalyses DeadArgumentEliminationPass::run(Module &M,
ModuleAnalysisManager &) {
// Integration header file must be provided for
// DAE to work on SPIR kernels.
if (CheckSpirKernels && !IntegrationHeaderFileName.getNumOccurrences())
return PreservedAnalyses::all();

bool Changed = false;

// First pass: Do a simple check to see if any functions can have their "..."
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,6 @@ void PassManagerBuilder::populateModulePassManager(
if (RunInliner) {
MPM.add(createGlobalOptimizerPass());
MPM.add(createGlobalDCEPass());
MPM.add(createDeadArgEliminationSYCLPass());
}

// If we are planning to perform ThinLTO later, let's not bloat the code with
Expand Down
1 change: 0 additions & 1 deletion llvm/test/Other/opt-O2-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@
; CHECK-NEXT: Branch Probability Analysis
; CHECK-NEXT: Block Frequency Analysis
; CHECK-NEXT: Dead Global Elimination
; CHECK-NEXT: Dead Argument Elimination for SPIR kernels in SYCL environment
; CHECK-NEXT: CallGraph Construction
; CHECK-NEXT: Globals Alias Analysis
; CHECK-NEXT: FunctionPass Manager
Expand Down
1 change: 0 additions & 1 deletion llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@
; CHECK-NEXT: Branch Probability Analysis
; CHECK-NEXT: Block Frequency Analysis
; CHECK-NEXT: Dead Global Elimination
; CHECK-NEXT: Dead Argument Elimination for SPIR kernels in SYCL environment
; CHECK-NEXT: CallGraph Construction
; CHECK-NEXT: Globals Alias Analysis
; CHECK-NEXT: FunctionPass Manager
Expand Down
1 change: 0 additions & 1 deletion llvm/test/Other/opt-O3-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@
; CHECK-NEXT: Branch Probability Analysis
; CHECK-NEXT: Block Frequency Analysis
; CHECK-NEXT: Dead Global Elimination
; CHECK-NEXT: Dead Argument Elimination for SPIR kernels in SYCL environment
; CHECK-NEXT: CallGraph Construction
; CHECK-NEXT: Globals Alias Analysis
; CHECK-NEXT: FunctionPass Manager
Expand Down
1 change: 0 additions & 1 deletion llvm/test/Other/opt-Os-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@
; CHECK-NEXT: Branch Probability Analysis
; CHECK-NEXT: Block Frequency Analysis
; CHECK-NEXT: Dead Global Elimination
; CHECK-NEXT: Dead Argument Elimination for SPIR kernels in SYCL environment
; CHECK-NEXT: CallGraph Construction
; CHECK-NEXT: Globals Alias Analysis
; CHECK-NEXT: FunctionPass Manager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
; RUN: opt < %s -deadargelim-sycl -S | FileCheck %s

; This test ensures dead arguments are not eliminated
; from a global function that is not a SYCL kernel.
; from a global function that is not a SPIR kernel.

; CHECK-NOT: !spir_kernel_omit_args

target triple = "spir64-unknown-unknown-sycldevice"

Expand Down
17 changes: 0 additions & 17 deletions llvm/test/Transforms/DeadArgElim/sycl-kernels-neg1.ll

This file was deleted.

13 changes: 0 additions & 13 deletions llvm/test/Transforms/DeadArgElim/sycl-kernels-neg2.ll

This file was deleted.

16 changes: 0 additions & 16 deletions llvm/test/Transforms/DeadArgElim/sycl-kernels-neg3.ll

This file was deleted.

18 changes: 0 additions & 18 deletions llvm/test/Transforms/DeadArgElim/sycl-kernels-neg4.ll

This file was deleted.

33 changes: 7 additions & 26 deletions llvm/test/Transforms/DeadArgElim/sycl-kernels.ll
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
; RUN: echo 'some code we want to preserve' > %t-int_header.h
; RUN: echo 'static constexpr const bool param_omit_table[] = {' >> %t-int_header.h
; RUN: echo ' // OMIT_TABLE_BEGIN' >> %t-int_header.h
; RUN: echo ' // SpirKernel1' >> %t-int_header.h
; RUN: echo ' false, false,' >> %t-int_header.h
; RUN: echo ' // SpirKernel2' >> %t-int_header.h
; RUN: echo ' false, false,' >> %t-int_header.h
; RUN: echo ' // OMIT_TABLE_END' >> %t-int_header.h
; RUN: echo '};' >> %t-int_header.h
; RUN: echo 'some code we want to preserve' >> %t-int_header.h
; RUN: opt < %s -deadargelim -S | FileCheck %s --check-prefixes=CHECK
; RUN: opt < %s -deadargelim-sycl -S -integr-header-file %t-int_header.h | FileCheck %s --check-prefixes=CHECK-SYCL
; RUN: cat %t-int_header.h | FileCheck %s --check-prefixes=CHECK-INT-HEADER
; RUN: opt < %s -deadargelim-sycl -S | FileCheck %s --check-prefixes=CHECK-SYCL

; This test checks eliminating dead arguments
; from SPIR kernel functions in SYCL environment.
Expand All @@ -25,10 +14,10 @@ define weak_odr spir_kernel void @SpirKernel1(float %arg1, float %arg2) {
; CHECK-NEXT: ret void
;
; CHECK-SYCL-LABEL: define {{[^@]+}}@SpirKernel1
; CHECK-SYCL-SAME: (float [[ARG1:%.*]])
; CHECK-SYCL-SAME: (float [[ARG1:%.*]]) !spir_kernel_omit_args ![[KERN_ARGS1:[0-9]]]
; CHECK-SYCL-NEXT: call void @foo(float [[ARG1]])
; CHECK-SYCL-NEXT: ret void
;

call void @foo(float %arg1)
ret void
}
Expand All @@ -40,23 +29,15 @@ define weak_odr spir_kernel void @SpirKernel2(float %arg1, float %arg2) {
; CHECK-NEXT: ret void
;
; CHECK-SYCL-LABEL: define {{[^@]+}}@SpirKernel2
; CHECK-SYCL-SAME: (float [[ARG2:%.*]])
; CHECK-SYCL-SAME: (float [[ARG2:%.*]]) !spir_kernel_omit_args ![[KERN_ARGS2:[0-9]]]
; CHECK-SYCL-NEXT: call void @foo(float [[ARG2]])
; CHECK-SYCL-NEXT: ret void
;

call void @foo(float %arg2)
ret void
}

; CHECK-INT-HEADER: some code we want to preserve
; CHECK-INT-HEADER: static constexpr const bool param_omit_table[] = {
; CHECK-INT-HEADER: // OMIT_TABLE_BEGIN
; CHECK-INT-HEADER: // SpirKernel1
; CHECK-INT-HEADER: false, true,
; CHECK-INT-HEADER: // SpirKernel2
; CHECK-INT-HEADER: true, false,
; CHECK-INT-HEADER: // OMIT_TABLE_END
; CHECK-INT-HEADER: };
; CHECK-INT-HEADER: some code we want to preserve
; CHECK-SYCL: ![[KERN_ARGS1]] = !{i1 false, i1 true}
; CHECK-SYCL: ![[KERN_ARGS2]] = !{i1 true, i1 false}

declare void @foo(float %arg)