Skip to content
Closed
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
10 changes: 7 additions & 3 deletions clang/test/Driver/linker-wrapper-sycl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,23 @@
// CHK-CMDS-NEXT: "{{.*}}llc" -filetype=obj -o [[LLCOUT:.*]] [[WRAPPEROUT]].bc
// CHK-CMDS-NEXT: "{{.*}}/ld" -- HOST_LINKER_FLAGS -dynamic-linker HOST_DYN_LIB -o a.out [[LLCOUT]] HOST_LIB_PATH HOST_STAT_LIB {{.*}}.o

// Check sycl-module-split-mode command line option.
// Check sycl-module-split-mode and sycl-spec-const-handling-mode command line options
// This option uses split library instead of sycl-post-link tool.
// RUN: clang-linker-wrapper -sycl-module-split-mode=auto -sycl-device-libraries=%t.devicelib.o -sycl-post-link-options="SYCL_POST_LINK_OPTIONS" -llvm-spirv-options="LLVM_SPIRV_OPTIONS" "--host-triple=x86_64-unknown-linux-gnu" "--triple=spir64" "--linker-path=/usr/bin/ld" "--" HOST_LINKER_FLAGS "-dynamic-linker" HOST_DYN_LIB "-o" "a.out" HOST_LIB_PATH HOST_STAT_LIB %t.o --dry-run 2>&1 | FileCheck -check-prefix=CHK-SPLIT-CMDS %s
// RUN: clang-linker-wrapper -sycl-module-split-mode=auto -sycl-spec-const-handling-mode=native -sycl-device-libraries=%t.devicelib.o -llvm-spirv-options="LLVM_SPIRV_OPTIONS" "--host-triple=x86_64-unknown-linux-gnu" "--triple=spir64" "--linker-path=/usr/bin/ld" "--" HOST_LINKER_FLAGS "-dynamic-linker" HOST_DYN_LIB "-o" "a.out" HOST_LIB_PATH HOST_STAT_LIB %t.o --dry-run 2>&1 | FileCheck -check-prefix=CHK-SPLIT-CMDS %s
// CHK-SPLIT-CMDS: "{{.*}}spirv-to-ir-wrapper" {{.*}} -o [[FIRSTLLVMLINKIN:.*]].bc --llvm-spirv-opts --spirv-preserve-auxdata --spirv-target-env=SPV-IR --spirv-builtin-format=global
// CHK-SPLIT-CMDS-NEXT: "{{.*}}llvm-link" [[FIRSTLLVMLINKIN]].bc -o [[FIRSTLLVMLINKOUT:.*]].bc --suppress-warnings
// CHK-SPLIT-CMDS-NEXT: "{{.*}}llvm-link" -only-needed [[FIRSTLLVMLINKOUT]].bc {{.*}}.bc -o [[SECONDLLVMLINKOUT:.*]].bc --suppress-warnings
// CHK-SPLIT-CMDS-NEXT: sycl-module-split: input: [[SECONDLLVMLINKOUT]].bc, output: [[SYCLMODULESPLITOUT:.*]].bc
// CHK-SPLIT-CMDS-NEXT: sycl-module-split: input: [[SECONDLLVMLINKOUT]].bc, output: [[SYCLMODULESPLITOUT:.*]].bc, split_mode: auto, output_assembly: false, output_prefix: , spec_const_mode: native
// CHK-SPLIT-CMDS-NEXT: "{{.*}}llvm-spirv"{{.*}} LLVM_SPIRV_OPTIONS -o [[SPIRVOUT:.*]].spv [[SYCLMODULESPLITOUT]].bc
// LLVM-SPIRV is not called in dry-run
// CHK-SPLIT-CMDS-NEXT: offload-wrapper: input: [[SPIRVOUT]].spv, output: [[WRAPPEROUT:.*]].bc
// CHK-SPLIT-CMDS-NEXT: "{{.*}}llc" -filetype=obj -o [[LLCOUT:.*]] [[WRAPPEROUT]].bc
// CHK-SPLIT-CMDS-NEXT: "{{.*}}/ld" -- HOST_LINKER_FLAGS -dynamic-linker HOST_DYN_LIB -o a.out [[LLCOUT]] HOST_LIB_PATH HOST_STAT_LIB {{.*}}.o

// Check incompatibility of -sycl-spec-const-handling-mode command line option with sycl-post-link tool path in clang-linker-wrapper.
// RUN: not clang-linker-wrapper -sycl-spec-const-handling-mode=native -sycl-device-libraries=%t.devicelib.o -llvm-spirv-options="LLVM_SPIRV_OPTIONS" "--host-triple=x86_64-unknown-linux-gnu" "--triple=spir64" "--linker-path=/usr/bin/ld" "--" HOST_LINKER_FLAGS "-dynamic-linker" HOST_DYN_LIB "-o" "a.out" HOST_LIB_PATH HOST_STAT_LIB %t.o --dry-run 2>&1 | FileCheck -check-prefix=CHK-SPEC-CONST-ERROR %s
// CHK-SPEC-CONST-ERROR: error: -sycl-spec-const-handling command line option should be used in conjunction with -sycl-module-split-mode command line option.

/// check for PIC for device wrap compilation when using -shared
// RUN: clang-linker-wrapper -sycl-device-libraries=%t.devicelib.o -sycl-post-link-options="SYCL_POST_LINK_OPTIONS" -llvm-spirv-options="LLVM_SPIRV_OPTIONS" "--host-triple=x86_64-unknown-linux-gnu" "--triple=spir64" "--linker-path=/usr/bin/ld" -shared "--" HOST_LINKER_FLAGS "-dynamic-linker" HOST_DYN_LIB "-o" "a.out" HOST_LIB_PATH HOST_STAT_LIB %t.o --dry-run 2>&1 | FileCheck -check-prefix=CHK-SHARED %s
// CHK-SHARED: "{{.*}}llc"{{.*}} -relocation-model=pic
Expand Down
45 changes: 27 additions & 18 deletions clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,26 +754,18 @@ runSYCLPostLinkTool(ArrayRef<StringRef> InputFiles, const ArgList &Args) {
static Expected<std::vector<module_split::SplitModule>>
runSYCLSplitLibrary(ArrayRef<StringRef> InputFiles, const ArgList &Args,
module_split::IRSplitMode Mode) {
std::vector<module_split::SplitModule> SplitModules;
if (DryRun) {
auto OutputFileOrErr = createOutputFile(
sys::path::filename(ExecutableName) + ".sycl.split.image", "bc");
if (!OutputFileOrErr)
return OutputFileOrErr.takeError();

StringRef OutputFilePath = *OutputFileOrErr;
auto InputFilesStr = llvm::join(InputFiles.begin(), InputFiles.end(), ",");
errs() << formatv("sycl-module-split: input: {0}, output: {1}\n",
InputFilesStr, OutputFilePath);
SplitModules.emplace_back(OutputFilePath, util::PropertySetRegistry(), "");
return SplitModules;
}

llvm::module_split::ModuleSplitterSettings Settings;
Settings.Mode = Mode;
Settings.OutputPrefix = "";
if (Args.hasArg(OPT_sycl_spec_const_handling_mode_EQ))
Settings.SpecConstantMode = convertStringToSpecConstMode(
Args.getLastArgValue(OPT_sycl_spec_const_handling_mode_EQ));

std::vector<module_split::SplitModule> SplitModules;
for (StringRef InputFile : InputFiles) {
if (DryRun)
break;

SMDiagnostic Err;
LLVMContext C;
std::unique_ptr<Module> M = parseIRFile(InputFile, Err, C);
Expand All @@ -790,7 +782,17 @@ runSYCLSplitLibrary(ArrayRef<StringRef> InputFiles, const ArgList &Args,
NewSplitModules.end());
}

if (Verbose) {
if (Verbose || DryRun) {
if (DryRun) {
auto OutputFileOrErr = createOutputFile(
sys::path::filename(ExecutableName) + ".sycl.split.image", "bc");
if (!OutputFileOrErr)
return OutputFileOrErr.takeError();

SplitModules.emplace_back(*OutputFileOrErr, util::PropertySetRegistry(),
"");
}

auto InputFilesStr = llvm::join(InputFiles.begin(), InputFiles.end(), ",");
std::string SplitOutputFilesStr;
for (size_t I = 0, E = SplitModules.size(); I != E; ++I) {
Expand All @@ -800,8 +802,9 @@ runSYCLSplitLibrary(ArrayRef<StringRef> InputFiles, const ArgList &Args,
SplitOutputFilesStr += SplitModules[I].ModuleFilePath;
}

errs() << formatv("sycl-module-split: input: {0}, output: {1}\n",
InputFilesStr, SplitOutputFilesStr);
errs() << formatv("sycl-module-split: input: {0}, output: {1}, {2}\n",
InputFilesStr, SplitOutputFilesStr,
convertSplitterSettingsToString(Settings));
}

return SplitModules;
Expand Down Expand Up @@ -2771,6 +2774,12 @@ int main(int Argc, char **Argv) {
SPIRVDumpDir = Dir;
}

if (Args.hasArg(OPT_sycl_spec_const_handling_mode_EQ) &&
!Args.hasArg(OPT_sycl_module_split_mode_EQ))
reportError(createStringError(
"-sycl-spec-const-handling command line option should be used in "
"conjunction with -sycl-module-split-mode command line option."));

{
llvm::TimeTraceScope TimeScope("Execute linker wrapper");

Expand Down
7 changes: 7 additions & 0 deletions clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ def sycl_module_split_mode_EQ :
Flags<[WrapperOnlyOption]>,
HelpText<"Option that turns on split library with the given split mode">;

def sycl_spec_const_handling_mode_EQ : Joined<["--", "-"], "sycl-spec-const-handling-mode=">,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

My understanding of when we should clang-linker-wrapper args is when we need to communicate information from the driver to clang-linker-wrapper, where in most cases that happens for user specified command-line args that effect how clang-linker-wrapper needs to act.

For this case, I'm not sure I see why we need the new flag. I don't see any user visible option for Clang to effect spec consts, only logic to set the -spec-const flag to sycl-post-link, which seems to be a triple-based calculation.

Also in this PR I don't see any changes to the driver to set this new flag.

Could you go into detail on why we need this flag and how we plan to modify the driver to set it?

Thanks

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on @sarnex comment here about the need for this mode.
I see the related code here

bool SpecConstsSupported = (!Triple.isNVPTX() && !Triple.isAMDGCN() &&

and the spec-const mode seems to rely on the target triple and nothing else and hence should be computed inside the clang-linker-wrapper.
@maksimsab please let me know if we are missing something here.

Thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. It needs to be redesigned.

Flags<[WrapperOnlyOption]>,
HelpText<"Specialization constant's handling mode. Modes: native, emulation, default_values. "
"Native mode lowers specialization constants to native SPIRV instructions. "
"Emulation mode removes specialization constants and replaces it with emulation. "
"default_values mode generates new device images which are copies of output devices but contain specialization constants replaced with default values from specialization ids.">;

// Special option to pass in llvm-spirv options
def llvm_spirv_options_EQ : Joined<["--", "-"], "llvm-spirv-options=">,
Flags<[WrapperOnlyOption]>,
Expand Down
9 changes: 9 additions & 0 deletions llvm/include/llvm/SYCLLowerIR/ModuleSplitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define LLVM_SYCLLOWERIR_MODULE_SPLITTER_H

#include "SYCLDeviceRequirements.h"
#include "SpecConstants.h"

#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -50,6 +51,8 @@ enum IRSplitMode {
// returned.
std::optional<IRSplitMode> convertStringToSplitMode(StringRef S);

StringRef convertSplitModeToString(IRSplitMode SM);

// A vector that contains all entry point functions in a split module.
using EntryPointSet = SetVector<Function *>;

Expand Down Expand Up @@ -221,6 +224,8 @@ class ModuleDesc {
return *Reqs;
}

bool processSpecConstants(SpecConstantsPass::HandlingMode Mode);

#ifndef NDEBUG
void verifyESIMDProperty() const;
void dump() const;
Expand Down Expand Up @@ -310,8 +315,12 @@ struct ModuleSplitterSettings {
IRSplitMode Mode;
bool OutputAssembly = false; // Bitcode or LLVM IR.
StringRef OutputPrefix;
std::optional<SpecConstantsPass::HandlingMode> SpecConstantMode;
};

SmallString<64>
convertSplitterSettingsToString(const ModuleSplitterSettings &S);

/// Parses the output table file from sycl-post-link tool.
Expected<std::vector<SplitModule>> parseSplitModulesFromFile(StringRef File);

Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/SYCLLowerIR/SpecConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ class SpecConstantsPass : public PassInfoMixin<SpecConstantsPass> {
HandlingMode Mode;
};

std::optional<SpecConstantsPass::HandlingMode>
convertStringToSpecConstMode(StringRef S);

StringRef convertSpecConstModeToString(SpecConstantsPass::HandlingMode HM);

bool checkModuleContainsSpecConsts(const Module &M);

} // namespace llvm
53 changes: 52 additions & 1 deletion llvm/lib/SYCLLowerIR/ModuleSplitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/GlobalDCE.h"
Expand Down Expand Up @@ -458,6 +459,20 @@ std::optional<IRSplitMode> convertStringToSplitMode(StringRef S) {
return It->second;
}

StringRef convertSplitModeToString(IRSplitMode SM) {
static const DenseMap<IRSplitMode, StringRef> Values = {
{SPLIT_PER_KERNEL, "kernel"},
{SPLIT_PER_TU, "source"},
{SPLIT_AUTO, "auto"},
{SPLIT_NONE, "none"}};

auto It = Values.find(SM);
if (It == Values.end())
llvm_unreachable("SplitMode value is unhandled!");

return It->second;
}

bool isESIMDFunction(const Function &F) {
return F.getMetadata(ESIMD_MARKER_MD) != nullptr;
}
Expand All @@ -467,6 +482,23 @@ cl::OptionCategory &getModuleSplitCategory() {
return ModuleSplitCategory;
}

bool ModuleDesc::processSpecConstants(SpecConstantsPass::HandlingMode Mode) {
Props.SpecConstsMet = false;
if (Mode == SpecConstantsPass::HandlingMode::default_values)
return false;

Props.SpecConstsMet = false;
ModulePassManager MPM;
ModuleAnalysisManager MAM;
SpecConstantsPass SCP(Mode);
MAM.registerPass([] { return PassInstrumentationAnalysis(); });
MPM.addPass(std::move(SCP));

PreservedAnalyses Res = MPM.run(*M, MAM);
Props.SpecConstsMet = !Res.areAllPreserved();
return Props.SpecConstsMet;
}

Error ModuleSplitterBase::verifyNoCrossModuleDeviceGlobalUsage() {
const Module &M = getInputModule();
// Early exit if there is only one group
Expand Down Expand Up @@ -1355,7 +1387,7 @@ Expected<std::vector<SplitModule>> parseSplitModulesFromFile(StringRef File) {

Expected<std::vector<SplitModule>>
splitSYCLModule(std::unique_ptr<Module> M, ModuleSplitterSettings Settings) {
ModuleDesc MD = std::move(M); // makeModuleDesc() ?
ModuleDesc MD = std::move(M);
// FIXME: false arguments are temporary for now.
auto Splitter = getDeviceCodeSplitter(std::move(MD), Settings.Mode,
/*IROutputOnly=*/false,
Expand All @@ -1368,6 +1400,13 @@ splitSYCLModule(std::unique_ptr<Module> M, ModuleSplitterSettings Settings) {
MD2.fixupLinkageOfDirectInvokeSimdTargets();

std::string OutIRFileName = (Settings.OutputPrefix + "_" + Twine(ID)).str();
// TODO: Presented processSpecConstants functionality should be invoked
// later combined with SPIRV Backend conversion. This is happening here
// until SPIRV translator is being used.
auto SCMode = Settings.SpecConstantMode;
if (SCMode.has_value())
MD2.processSpecConstants(SCMode.value());

auto SplittedImageOrErr =
saveModuleDesc(MD2, OutIRFileName, Settings.OutputAssembly);
if (!SplittedImageOrErr)
Expand Down Expand Up @@ -1413,5 +1452,17 @@ bool canBeImportedFunction(const Function &F) {
return ReturnValue;
}

SmallString<64>
convertSplitterSettingsToString(const ModuleSplitterSettings &S) {
StringRef SCMStr = S.SpecConstantMode
? convertSpecConstModeToString(*S.SpecConstantMode)
: "";
return formatv("split_mode: {0}, output_assembly: {1}, output_prefix: {2}, "
"spec_const_mode: {3}",
convertSplitModeToString(S.Mode), S.OutputAssembly,
S.OutputPrefix, SCMStr)
.sstr<64>();
}

} // namespace module_split
} // namespace llvm
46 changes: 36 additions & 10 deletions llvm/lib/SYCLLowerIR/SpecConstants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
//===----------------------------------------------------------------------===//

#include "llvm/SYCLLowerIR/SpecConstants.h"
#include "llvm/SYCLLowerIR/Support.h"

#include "llvm/ADT/APInt.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
Expand All @@ -23,6 +21,7 @@
#include "llvm/IR/PatternMatch.h"
#include "llvm/TargetParser/Triple.h"

#include <cassert>
#include <vector>

#define DEBUG_TYPE "SpecConst"
Expand Down Expand Up @@ -111,38 +110,37 @@ StringRef getStringLiteralArg(const CallInst *CI, unsigned ArgNo,
V = X;
return isa<AllocaInst>(V);
};
AssertRelease(ValueIsAlloca(TmpPtr), "unexpected instruction type");
assert(ValueIsAlloca(TmpPtr) && "unexpected instruction type");

// find the store of the literal address into TmpPtr
StoreInst *Store = nullptr;

for (User *U : TmpPtr->users()) {
if (StoreInst *St = dyn_cast<StoreInst>(U)) {
AssertRelease(!Store, "single store expected");
assert(!Store && "single store expected");
Store = St;
#ifndef NDEBUG
break;
#endif // NDEBUG
}
}
AssertRelease(Store, "unexpected spec const IR pattern 0");
assert(Store && "unexpected spec const IR pattern 0");
DelInsts.push_back(Store);
#ifndef NDEBUG
// verify there are no intervening stores/calls
AssertRelease(L->getParent() == Store->getParent(), "same BB expected");
assert(L->getParent() == Store->getParent() && "same BB expected");

for (const Instruction *I = Store->getNextNode(); I; I = I->getNextNode()) {
if (I == L) {
DelInsts.push_back(L);
L = nullptr; // mark as met
break;
}
AssertRelease(!I->mayHaveSideEffects(),
"unexpected spec const IR pattern 1");
assert(!I->mayHaveSideEffects() && "unexpected spec const IR pattern 1");
}
AssertRelease(!L, "load not met after the store");
assert(!L && "load not met after the store");
#endif // NDEBUG
AssertRelease(Store, "store not met");
assert(Store && "store not met");
V = Store->getValueOperand()->stripPointerCasts();
}
const Constant *Init = cast<GlobalVariable>(V)->getInitializer();
Expand Down Expand Up @@ -1089,6 +1087,34 @@ bool SpecConstantsPass::collectSpecConstantDefaultValuesMetadata(
return true;
}

std::optional<SpecConstantsPass::HandlingMode>
llvm::convertStringToSpecConstMode(StringRef S) {
static const StringMap<SpecConstantsPass::HandlingMode> Values = {
{"default_values", SpecConstantsPass::HandlingMode::default_values},
{"emulation", SpecConstantsPass::HandlingMode::emulation},
{"native", SpecConstantsPass::HandlingMode::native}};

auto It = Values.find(S);
if (It == Values.end())
return std::nullopt;

return It->second;
}

StringRef
llvm::convertSpecConstModeToString(llvm::SpecConstantsPass::HandlingMode HM) {
static const DenseMap<SpecConstantsPass::HandlingMode, StringRef> Values = {
{SpecConstantsPass::HandlingMode::default_values, "default_values"},
{SpecConstantsPass::HandlingMode::emulation, "emulation"},
{SpecConstantsPass::HandlingMode::native, "native"}};

auto It = Values.find(HM);
if (It == Values.end())
llvm_unreachable("HandlingMode value is unhandled!");

return It->second;
}

bool llvm::checkModuleContainsSpecConsts(const Module &M) {
for (const Function &F : M.functions()) {
if (F.getName().starts_with(SYCL_GET_SCALAR_2020_SPEC_CONST_VAL) ||
Expand Down
Loading