Skip to content

Commit 29abe37

Browse files
authored
[SYCL] Implement specialization constants. (#1356)
Based on https://github.com/codeplaysoftware/standards-proposals/blob/master/spec-constant/index.md * [SYCL] PI changes: 1. Add specialization constant API to the SYCL RT Plugin Interface. New PI API added: pi_result piProgramSetSpecializationConstant(pi_program prog, pi_uint32 spec_id, size_t spec_size, const void *spec_value); 2. Add property set fields to the binary image descriptor, bump PI version. This change breaks backward binary compatibility of device binary image descriptors. 3. Add convenience C++ wrappers for PI binary image hierarchy objects. * [SYCL] Support device binary properties and file tables in the offload wrapper. 1. New option - "-properties=<file>". <file> must be a property set registry file, as defined by llvm/Support/PropertySetIO.h. The wrapper will add the property sets to the binary image descriptor and the them available to the runtime. 2. New options - "-batch". With this option the only input can be a file table, as defined by llvm/Support/SimpleTable.h. Column names are a part of interface between this tool and the sycl-post-link, which produces the file table. 3. Binary image descriptor LLVM type updated to resemble changes in Plugin Interface v1.2. * [SYCL] Specialization constants support in the Front End. 1. Detect kernel lambda object captures corresponding to specialization constants and (a) don't create kernel arguments for them (b) generate specializations of the SpecConstantInfo structure into the integration header. 2. Recognize the __unique_stable_name intrinsic and replace it with a string literal uniquely identifying the type of the typename template parameter to this intrinsic. 3. FE-related changes in the runtime: - new SpecConstantInfo templated struct for type->name translation for specialization constants used by integration header - define the __sycl_fe_getStableUniqueTypeName intrinsic * [SYCL] Add specialization constant support in SYCL runtime. 1. Define SYCL API (sycl/include/CL/sycl/experimental/spec_constant.hpp) 2. Add convenience C++ wrappers for PI device binary structures and refactor runtime to use the wrappers. Get rid of custom deleters for binary images. 3. Implement SYCL spec constant APIs in program an program manager. * [SYCL] Use file-table-tform in SYCL offload processing in clang driver. Clang driver's design can't handily model (1) multiple inputs/outputs in the action graph. Because of that, for example, sycl-post-link tool is invoked twice - once to to split the code and produce multiple bitcode files, and secondly - to generate symbol files for the split modules. (2) "Clusters" of inputs/outputs, when subsets of inputs/outputs are associated and describe different aspects of the same data. Example of such clustering is the split module + its symbol file above. Clustering would require support both in the driver and the tools invoked in response to actions. This commit moves SYCL offload processing to the "file table concept." sycl-post-link instead of (1) being invoked n times, once per each output type requested (once for device split and once for symbol file generation) (2) outputting multiple file lists each listing outputs from the corresponding invocation above is now invoked once and produces single file table output. E.g. [Code|Symbols|Properties] a_0.bc|a_0.sym|a_0.props a_1.bc|a_1.sym|a_1.props This solves both problems - multiple input/output and clustering. Combined with the file-table-tform tool, this allows for efficent handling of multiple clusters of files (each represented as a row in the table file) in the clang driver infrastructure. For example, there is a real offload processing problem: step1. sycl-post-link outputs N clusters of files step2. "Code" file of each cluster resuilting from step1 ({a_0.bc, a_1.bc} in the example above) must undergo further transformations - translation to SPIRV and optional ahead-of-time compilation. step3. In each cluster resulting from step1 the "Code" file needs to be replaced with the result of step2 step4. All the clusters are processed by the ClangOffloadWrapper tool, which needs to know how files are distributed into clusters and what is the roles of each file in a cluster - whether it is "Code", "Symbol" or "Properties". To solve this, the following action graph is constructed in the clang driver: column:"Code" t1 -> [file-table-tform:extract column] -> t1a -> [for-each:] -> t1b llvm-spirv aot-comp t1 \ column:"Code" [file-table-tform:replace column] -> t2 -> [ClangOffloadWrapper] / t1b where t1b is ["Code"] and t2 is [Code|Symbols|Properties] a_0.bin a_0.bin|a_0.sym|a_0.props a_1.bin a_1.bin|a_1.sym|a_1.props Note that the graph does not change with growing number of clusters, neither it changes when more files are added to each cluster (e.g. a "Manifest" file). * [SYCL] Process specialization constants in sycl-post-link tool. Add a spec constant lowering pass to sycl-post-link tool. Support file table output format. * [SYCL] Temporarily disable spec_const_hw.cpp on CPU. CPU OpenCL Runtime on build machines is not updated yet. Signed-off-by: Konstantin S Bobrovsky <[email protected]>
1 parent 9be1566 commit 29abe37

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+3636
-725
lines changed

clang/include/clang/Driver/Action.h

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "llvm/ADT/SmallVector.h"
1818
#include "llvm/ADT/StringRef.h"
1919
#include "llvm/ADT/iterator_range.h"
20+
#include <initializer_list>
2021
#include <string>
2122

2223
namespace llvm {
@@ -78,9 +79,10 @@ class Action {
7879
SYCLPostLinkJobClass,
7980
PartialLinkJobClass,
8081
BackendCompileJobClass,
82+
FileTableTformJobClass,
8183

8284
JobClassFirst = PreprocessJobClass,
83-
JobClassLast = BackendCompileJobClass
85+
JobClassLast = FileTableTformJobClass
8486
};
8587

8688
// The offloading kind determines if this action is binded to a particular
@@ -679,6 +681,13 @@ class SYCLPostLinkJobAction : public JobAction {
679681
static bool classof(const Action *A) {
680682
return A->getKind() == SYCLPostLinkJobClass;
681683
}
684+
685+
void setRTSetsSpecConstants(bool Val) { RTSetsSpecConsts = Val; }
686+
687+
bool getRTSetsSpecConstants() const { return RTSetsSpecConsts; }
688+
689+
private:
690+
bool RTSetsSpecConsts = true;
682691
};
683692

684693
class PartialLinkJobAction : public JobAction {
@@ -705,6 +714,47 @@ class BackendCompileJobAction : public JobAction {
705714
}
706715
};
707716

717+
// Represents a file table transformation action. The order of inputs to a
718+
// FileTableTformJobAction at construction time must accord with the tforms
719+
// added later - some tforms "consume" inputs. For example, "replace column"
720+
// needs another file to read the replacement column from.
721+
class FileTableTformJobAction : public JobAction {
722+
void anchor() override;
723+
724+
public:
725+
struct Tform {
726+
enum Kind { EXTRACT, EXTRACT_DROP_TITLE, REPLACE };
727+
728+
Tform() = default;
729+
Tform(Kind K, std::initializer_list<StringRef> Args) : TheKind(K) {
730+
for (auto A : Args)
731+
TheArgs.emplace_back(A.str());
732+
}
733+
734+
Kind TheKind;
735+
SmallVector<std::string, 2> TheArgs;
736+
};
737+
738+
FileTableTformJobAction(Action *Input, types::ID OutputType);
739+
FileTableTformJobAction(ActionList &Inputs, types::ID OutputType);
740+
741+
// Deletes all columns except the one with given name.
742+
void addExtractColumnTform(StringRef ColumnName, bool WithColTitle = true);
743+
744+
// Replaces a column with title <From> in this table with a column with title
745+
// <To> from another file table passed as input to this action.
746+
void addReplaceColumnTform(StringRef From, StringRef To);
747+
748+
static bool classof(const Action *A) {
749+
return A->getKind() == FileTableTformJobClass;
750+
}
751+
752+
const ArrayRef<Tform> getTforms() const { return Tforms; }
753+
754+
private:
755+
SmallVector<Tform, 2> Tforms; // transformation actions requested
756+
};
757+
708758
} // namespace driver
709759
} // namespace clang
710760

clang/include/clang/Driver/ToolChain.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class ToolChain {
147147
mutable std::unique_ptr<Tool> SYCLPostLink;
148148
mutable std::unique_ptr<Tool> PartialLink;
149149
mutable std::unique_ptr<Tool> BackendCompiler;
150+
mutable std::unique_ptr<Tool> FileTableTform;
150151

151152
Tool *getClang() const;
152153
Tool *getFlang() const;
@@ -161,6 +162,7 @@ class ToolChain {
161162
Tool *getSYCLPostLink() const;
162163
Tool *getPartialLink() const;
163164
Tool *getBackendCompiler() const;
165+
Tool *getTableTform() const;
164166

165167
mutable std::unique_ptr<SanitizerArgs> SanitizerArguments;
166168
mutable std::unique_ptr<XRayArgs> XRayArguments;

clang/include/clang/Driver/Types.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ TYPE("spirv", SPIRV, INVALID, "spv", phases
103103
TYPE("sycl-header", SYCL_Header, INVALID, "h", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
104104
TYPE("sycl-fatbin", SYCL_FATBIN, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
105105
TYPE("tempfilelist", Tempfilelist, INVALID, "txt", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
106-
TYPE("tempentriesfilelist", TempEntriesfilelist, INVALID, "txt", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
106+
TYPE("tempfiletable", Tempfiletable,INVALID, "table", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
107107
TYPE("tempAOCOfilelist", TempAOCOfilelist, INVALID, "txt", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
108108
TYPE("archive", Archive, INVALID, "a", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
109109
TYPE("wholearchive", WholeArchive, INVALID, "a", phases::Compile, phases::Backend, phases::Assemble, phases::Link)

clang/include/clang/Sema/Sema.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,9 @@ class SYCLIntegrationHeader {
339339
/// invocation descriptor has finished.
340340
void endKernel();
341341

342+
/// Registers a specialization constant to emit info for it into the header.
343+
void addSpecConstant(StringRef IDName, QualType IDType);
344+
342345
private:
343346
// Kernel actual parameter descriptor.
344347
struct KernelParamDesc {
@@ -407,6 +410,13 @@ class SYCLIntegrationHeader {
407410
/// SYCLIntegrationHeader::startKernel
408411
SmallVector<KernelDesc, 4> KernelDescs;
409412

413+
using SpecConstID = std::pair<QualType, std::string>;
414+
415+
/// Keeps specialization constants met in the translation unit. Maps spec
416+
/// constant's ID type to generated unique name. Duplicates are removed at
417+
/// integration header emission time.
418+
llvm::SmallVector<SpecConstID, 4> SpecConsts;
419+
410420
/// Used for emitting diagnostics.
411421
DiagnosticsEngine &Diag;
412422

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "CGObjCRuntime.h"
1818
#include "CGOpenMPRuntime.h"
1919
#include "CGRecordLayout.h"
20+
#include "CGSYCLRuntime.h"
2021
#include "CodeGenFunction.h"
2122
#include "CodeGenModule.h"
2223
#include "ConstantEmitter.h"

clang/lib/Driver/Action.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ const char *Action::getClassName(ActionClass AC) {
5353
return "partial-link";
5454
case BackendCompileJobClass:
5555
return "backend-compiler";
56+
case FileTableTformJobClass:
57+
return "file-table-tform";
5658
}
5759

5860
llvm_unreachable("invalid class");
@@ -473,3 +475,23 @@ BackendCompileJobAction::BackendCompileJobAction(ActionList &Inputs,
473475
BackendCompileJobAction::BackendCompileJobAction(Action *Input,
474476
types::ID Type)
475477
: JobAction(BackendCompileJobClass, Input, Type) {}
478+
479+
void FileTableTformJobAction::anchor() {}
480+
481+
FileTableTformJobAction::FileTableTformJobAction(Action *Input, types::ID Type)
482+
: JobAction(FileTableTformJobClass, Input, Type) {}
483+
484+
FileTableTformJobAction::FileTableTformJobAction(ActionList &Inputs,
485+
types::ID Type)
486+
: JobAction(FileTableTformJobClass, Inputs, Type) {}
487+
488+
void FileTableTformJobAction::addExtractColumnTform(StringRef ColumnName,
489+
bool WithColTitle) {
490+
auto K = WithColTitle ? Tform::EXTRACT : Tform::EXTRACT_DROP_TITLE;
491+
Tforms.emplace_back(Tform(K, {ColumnName}));
492+
}
493+
494+
void FileTableTformJobAction::addReplaceColumnTform(StringRef From,
495+
StringRef To) {
496+
Tforms.emplace_back(Tform(Tform::REPLACE, {From, To}));
497+
}

clang/lib/Driver/Compilation.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/Option/OptSpecifier.h"
2424
#include "llvm/Option/Option.h"
2525
#include "llvm/Support/FileSystem.h"
26+
#include "llvm/Support/SimpleTable.h"
2627
#include "llvm/Support/raw_ostream.h"
2728
#include <cassert>
2829
#include <fstream>
@@ -136,12 +137,29 @@ bool Compilation::CleanupFileList(const TempFileList &Files,
136137
// Temporary file lists contain files that need to be cleaned. The
137138
// file containing the information is also removed
138139
if (File.second == types::TY_Tempfilelist ||
139-
File.second == types::TY_TempEntriesfilelist) {
140-
std::ifstream ListFile(File.first);
141-
if (ListFile) {
142-
// These are temporary files and need to be removed.
140+
File.second == types::TY_Tempfiletable) {
141+
// These are temporary files and need to be removed.
142+
bool IsTable = File.second == types::TY_Tempfiletable;
143+
144+
if (IsTable) {
145+
if (llvm::sys::fs::exists(File.first)) {
146+
auto T = llvm::util::SimpleTable::read(File.first);
147+
if (!T) {
148+
Success = false;
149+
continue;
150+
}
151+
std::vector<std::string> TmpFileNames;
152+
T->get()->linearize(TmpFileNames);
153+
154+
for (const auto &TmpFileName : TmpFileNames) {
155+
if (!TmpFileName.empty())
156+
Success &= CleanupFile(TmpFileName.c_str(), IssueErrors);
157+
}
158+
}
159+
} else {
160+
std::ifstream ListFile(File.first);
143161
std::string TmpFileName;
144-
while(std::getline(ListFile, TmpFileName) && !TmpFileName.empty())
162+
while (std::getline(ListFile, TmpFileName) && !TmpFileName.empty())
145163
Success &= CleanupFile(TmpFileName.c_str(), IssueErrors);
146164
}
147165
}

0 commit comments

Comments
 (0)