|
| 1 | +//===---- CompileTimePropertiesPass.cpp - SYCL Compile Time Props Pass ----===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | +// See comments in the header. |
| 9 | +//===----------------------------------------------------------------------===// |
| 10 | + |
| 11 | +#include "CompileTimePropertiesPass.h" |
| 12 | +#include "DeviceGlobals.h" |
| 13 | + |
| 14 | +#include "llvm/ADT/APInt.h" |
| 15 | +#include "llvm/ADT/StringMap.h" |
| 16 | +#include "llvm/ADT/StringRef.h" |
| 17 | +#include "llvm/IR/Module.h" |
| 18 | + |
| 19 | +using namespace llvm; |
| 20 | + |
| 21 | +namespace { |
| 22 | + |
| 23 | +constexpr StringRef SYCL_HOST_ACCESS_ATTR = "host_access"; |
| 24 | + |
| 25 | +constexpr StringRef SPIRV_DECOR_MD_KIND = "spirv.Decorations"; |
| 26 | +// The corresponding SPIR-V OpCode for the host_access property is documented |
| 27 | +// in the SPV_INTEL_global_variable_decorations design document: |
| 28 | +// https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/DeviceGlobal/SPV_INTEL_global_variable_decorations.asciidoc#decoration |
| 29 | +constexpr uint32_t SPIRV_HOST_ACCESS_DECOR = 6147; |
| 30 | +constexpr uint32_t SPIRV_HOST_ACCESS_DEFAULT_VALUE = 2; // Read/Write |
| 31 | + |
| 32 | +enum class DecorValueTy { |
| 33 | + uint32, |
| 34 | + boolean, |
| 35 | +}; |
| 36 | + |
| 37 | +struct Decor { |
| 38 | + uint32_t Code; |
| 39 | + DecorValueTy Type; |
| 40 | +}; |
| 41 | + |
| 42 | +#define SYCL_COMPILE_TIME_PROPERTY(PropertyName, Decoration, ValueType) \ |
| 43 | + {PropertyName, {Decoration, ValueType}}, |
| 44 | + |
| 45 | +const StringMap<Decor> SpirvDecorMap = { |
| 46 | +#include "CompileTimeProperties.def" |
| 47 | +}; |
| 48 | +#undef SYCL_COMPILE_TIME_PROPERTY |
| 49 | + |
| 50 | +/// Builds a metadata node for a SPIR-V decoration (both decoration code |
| 51 | +/// and value are \c uint32_t integers). |
| 52 | +/// |
| 53 | +/// @param Ctx [in] the LLVM Context. |
| 54 | +/// @param OpCode [in] the SPIR-V OpCode code. |
| 55 | +/// @param Value [in] the SPIR-V decoration value. |
| 56 | +/// |
| 57 | +/// @returns a pointer to the metadata node created for the required decoration |
| 58 | +/// and its value. |
| 59 | +MDNode *buildSpirvDecorMetadata(LLVMContext &Ctx, uint32_t OpCode, |
| 60 | + uint32_t Value) { |
| 61 | + auto *Ty = Type::getInt32Ty(Ctx); |
| 62 | + SmallVector<Metadata *, 2> MD; |
| 63 | + MD.push_back(ConstantAsMetadata::get( |
| 64 | + Constant::getIntegerValue(Ty, APInt(32, OpCode)))); |
| 65 | + MD.push_back( |
| 66 | + ConstantAsMetadata::get(Constant::getIntegerValue(Ty, APInt(32, Value)))); |
| 67 | + return MDNode::get(Ctx, MD); |
| 68 | +} |
| 69 | + |
| 70 | +/// Builds a metadata node for a SPIR-V decoration (both decoration code |
| 71 | +/// and value are \c uint32_t integers, and the secondary extra operand is a |
| 72 | +/// string). |
| 73 | +/// |
| 74 | +/// @param Ctx [in] the LLVM Context. |
| 75 | +/// @param OpCode [in] the SPIR-V OpCode code. |
| 76 | +/// @param Value [in] the SPIR-V decoration value. |
| 77 | +/// @param Secondary [in] the secondary "extra operands" (\c StringRef). |
| 78 | +/// |
| 79 | +/// @returns a pointer to the metadata node created for the required decoration |
| 80 | +/// and its value. |
| 81 | +MDNode *buildSpirvDecorMetadata(LLVMContext &Ctx, uint32_t OpCode, |
| 82 | + uint32_t Value, StringRef Secondary) { |
| 83 | + auto *Ty = Type::getInt32Ty(Ctx); |
| 84 | + SmallVector<Metadata *, 3> MD; |
| 85 | + MD.push_back(ConstantAsMetadata::get( |
| 86 | + Constant::getIntegerValue(Ty, APInt(32, OpCode)))); |
| 87 | + MD.push_back( |
| 88 | + ConstantAsMetadata::get(Constant::getIntegerValue(Ty, APInt(32, Value)))); |
| 89 | + MD.push_back(MDString::get(Ctx, Secondary)); |
| 90 | + return MDNode::get(Ctx, MD); |
| 91 | +} |
| 92 | + |
| 93 | +} // anonymous namespace |
| 94 | + |
| 95 | +PreservedAnalyses CompileTimePropertiesPass::run(Module &M, |
| 96 | + ModuleAnalysisManager &MAM) { |
| 97 | + LLVMContext &Ctx = M.getContext(); |
| 98 | + unsigned MDKindID = Ctx.getMDKindID(SPIRV_DECOR_MD_KIND); |
| 99 | + bool CompileTimePropertiesMet = false; |
| 100 | + |
| 101 | + // Let's process all the globals |
| 102 | + for (auto &GV : M.globals()) { |
| 103 | + // we suppose the enumeration orders in every enumeration in the SYCL |
| 104 | + // headers are the same as in the descriptions of the corresponding |
| 105 | + // decorations in the SPV_INTEL_* extensions. |
| 106 | + SmallVector<Metadata *, 8> MDOps; |
| 107 | + for (auto &Attribute : GV.getAttributes()) { |
| 108 | + // Currently, only string attributes are supported |
| 109 | + if (!Attribute.isStringAttribute()) |
| 110 | + continue; |
| 111 | + auto DecorIt = SpirvDecorMap.find(Attribute.getKindAsString()); |
| 112 | + if (DecorIt == SpirvDecorMap.end()) |
| 113 | + continue; |
| 114 | + auto Decor = DecorIt->second; |
| 115 | + auto DecorCode = Decor.Code; |
| 116 | + auto DecorValue = Decor.Type == DecorValueTy::uint32 |
| 117 | + ? getAttributeAsInteger<uint32_t>(Attribute) |
| 118 | + : hasProperty(Attribute); |
| 119 | + MDOps.push_back(buildSpirvDecorMetadata(Ctx, DecorCode, DecorValue)); |
| 120 | + } |
| 121 | + |
| 122 | + // Some properties should be handled specially. |
| 123 | + |
| 124 | + // The host_access property is handled specially for device global variables |
| 125 | + // because the SPIR-V decoration requires two "extra operands". The second |
| 126 | + // SPIR-V operand is the "name" (the value of the "sycl-unique-id" property) |
| 127 | + // of the variable. |
| 128 | + if (isDeviceGlobalVariable(GV)) { |
| 129 | + auto HostAccessDecorValue = |
| 130 | + GV.hasAttribute(SYCL_HOST_ACCESS_ATTR) |
| 131 | + ? getAttributeAsInteger<uint32_t>(GV, SYCL_HOST_ACCESS_ATTR) |
| 132 | + : SPIRV_HOST_ACCESS_DEFAULT_VALUE; |
| 133 | + auto VarName = getGlobalVariableUniqueId(GV); |
| 134 | + MDOps.push_back(buildSpirvDecorMetadata(Ctx, SPIRV_HOST_ACCESS_DECOR, |
| 135 | + HostAccessDecorValue, VarName)); |
| 136 | + } |
| 137 | + |
| 138 | + // Add the generated metadata to the variable |
| 139 | + if (!MDOps.empty()) { |
| 140 | + GV.addMetadata(MDKindID, *MDNode::get(Ctx, MDOps)); |
| 141 | + CompileTimePropertiesMet = true; |
| 142 | + } |
| 143 | + } |
| 144 | + |
| 145 | + // The pass just adds some metadata to the module, it should not ruin |
| 146 | + // any analysis, but we need return PreservedAnalyses::none() to inform |
| 147 | + // the caller that at least one compile-time property was met. |
| 148 | + return CompileTimePropertiesMet ? PreservedAnalyses::none() |
| 149 | + : PreservedAnalyses::all(); |
| 150 | +} |
0 commit comments