@@ -93,6 +93,15 @@ MDNode *buildSpirvDecorMetadata(LLVMContext &Ctx, uint32_t OpCode,
9393 return MDNode::get (Ctx, MD);
9494}
9595
96+ // / Gets the string value in a global variable. If the parameter is not a global
97+ // / variable or it does not contain string data, then \c None is returned.
98+ // /
99+ // / @param StringV [in] the LLVM value of supposed \c GlobalVariable type with
100+ // / a string value.
101+ // /
102+ // / @returns a \c StringRef with the string contained in \c StringV and \c None
103+ // / if \c StringV is not a \c GlobalVariable or does not contain string
104+ // / data.
96105Optional<StringRef> getGlobalVariableString (const Value *StringV) {
97106 if (const auto *StringGV = dyn_cast<GlobalVariable>(StringV))
98107 if (const auto *StringData =
@@ -102,6 +111,106 @@ Optional<StringRef> getGlobalVariableString(const Value *StringV) {
102111 return {};
103112}
104113
114+ // / Tries to generate a SPIR-V decorate metadata node from an attribute. If
115+ // / the attribute is unknown \c nullptr will be returned.
116+ // /
117+ // / @param Ctx [in] the LLVM context.
118+ // / @param Attr [in] the LLVM attribute to generate metadata for.
119+ // /
120+ // / @returns a pointer to a new metadata node if \c Attr is an attribute with a
121+ // / known corresponding SPIR-V decorate and the arguments are valid.
122+ // / Otherwise \c nullptr is returned.
123+ MDNode *attributeToDecorateMetadata (LLVMContext &Ctx, const Attribute &Attr) {
124+ // Currently, only string attributes are supported
125+ if (!Attr.isStringAttribute ())
126+ return nullptr ;
127+ auto DecorIt = SpirvDecorMap.find (Attr.getKindAsString ());
128+ if (DecorIt == SpirvDecorMap.end ())
129+ return nullptr ;
130+ Decor DecorFound = DecorIt->second ;
131+ uint32_t DecorCode = DecorFound.Code ;
132+ switch (DecorFound.Type ) {
133+ case DecorValueTy::uint32:
134+ return buildSpirvDecorMetadata (Ctx, DecorCode,
135+ getAttributeAsInteger<uint32_t >(Attr));
136+ case DecorValueTy::boolean:
137+ return buildSpirvDecorMetadata (Ctx, DecorCode, hasProperty (Attr));
138+ default :
139+ llvm_unreachable (" Unhandled decorator type." );
140+ }
141+ }
142+
143+ // / Tries to generate a SPIR-V execution mode metadata node from an attribute.
144+ // / If the attribute is unknown \c None will be returned.
145+ // /
146+ // / @param M [in] the LLVM module.
147+ // / @param Attr [in] the LLVM attribute to generate metadata for.
148+ // /
149+ // / @returns a pair with the name of the resulting metadata and a pointer to
150+ // / the metadata node with its values if the attribute has a
151+ // / corresponding SPIR-V execution mode. Otherwise \c None is returned.
152+ Optional<std::pair<std::string, MDNode *>>
153+ attributeToExecModeMetadata (Module &M, const Attribute &Attr) {
154+ LLVMContext &Ctx = M.getContext ();
155+ const DataLayout &DLayout = M.getDataLayout ();
156+
157+ // Currently, only string attributes are supported
158+ if (!Attr.isStringAttribute ())
159+ return None;
160+ StringRef AttrKindStr = Attr.getKindAsString ();
161+ // Early exit if it is not a sycl-* attribute.
162+ if (!AttrKindStr.startswith (" sycl-" ))
163+ return None;
164+
165+ if (AttrKindStr == " sycl-work-group-size" ||
166+ AttrKindStr == " sycl-work-group-size-hint" ) {
167+ // Split values in the comma-separated list integers.
168+ SmallVector<StringRef, 3 > ValStrs;
169+ Attr.getValueAsString ().split (ValStrs, ' ,' );
170+
171+ assert (ValStrs.size () <= 3 &&
172+ " sycl-work-group-size and sycl-work-group-size-hint currently only "
173+ " support up to three values" );
174+
175+ // SYCL work-group sizes must be reversed for SPIR-V.
176+ std::reverse (ValStrs.begin (), ValStrs.end ());
177+
178+ // Use integer pointer size as closest analogue to size_t.
179+ IntegerType *IntPtrTy = DLayout.getIntPtrType (Ctx);
180+ IntegerType *SizeTTy = Type::getIntNTy (Ctx, IntPtrTy->getBitWidth ());
181+ unsigned SizeTBitSize = SizeTTy->getBitWidth ();
182+
183+ // Get the integers from the strings.
184+ SmallVector<Metadata *, 3 > MDVals;
185+ for (StringRef ValStr : ValStrs)
186+ MDVals.push_back (ConstantAsMetadata::get (Constant::getIntegerValue (
187+ SizeTTy, APInt (SizeTBitSize, ValStr, 10 ))));
188+
189+ // The SPIR-V translator expects 3 values, so we pad the remaining
190+ // dimensions with 1.
191+ for (size_t I = MDVals.size (); I < 3 ; ++I)
192+ MDVals.push_back (ConstantAsMetadata::get (
193+ Constant::getIntegerValue (SizeTTy, APInt (SizeTBitSize, 1 ))));
194+
195+ const char *MDName = (AttrKindStr == " sycl-work-group-size" )
196+ ? " reqd_work_group_size"
197+ : " work_group_size_hint" ;
198+ return std::pair<std::string, MDNode *>(MDName, MDNode::get (Ctx, MDVals));
199+ }
200+
201+ if (AttrKindStr == " sycl-sub-group-size" ) {
202+ uint32_t SubGroupSize = getAttributeAsInteger<uint32_t >(Attr);
203+ IntegerType *Ty = Type::getInt32Ty (Ctx);
204+ Metadata *MDVal = ConstantAsMetadata::get (
205+ Constant::getIntegerValue (Ty, APInt (32 , SubGroupSize)));
206+ SmallVector<Metadata *, 1 > MD{MDVal};
207+ return std::pair<std::string, MDNode *>(" intel_reqd_sub_group_size" ,
208+ MDNode::get (Ctx, MD));
209+ }
210+
211+ return None;
212+ }
213+
105214} // anonymous namespace
106215
107216PreservedAnalyses CompileTimePropertiesPass::run (Module &M,
@@ -117,18 +226,9 @@ PreservedAnalyses CompileTimePropertiesPass::run(Module &M,
117226 // decorations in the SPV_INTEL_* extensions.
118227 SmallVector<Metadata *, 8 > MDOps;
119228 for (auto &Attribute : GV.getAttributes ()) {
120- // Currently, only string attributes are supported
121- if (!Attribute.isStringAttribute ())
122- continue ;
123- auto DecorIt = SpirvDecorMap.find (Attribute.getKindAsString ());
124- if (DecorIt == SpirvDecorMap.end ())
125- continue ;
126- auto Decor = DecorIt->second ;
127- auto DecorCode = Decor.Code ;
128- auto DecorValue = Decor.Type == DecorValueTy::uint32
129- ? getAttributeAsInteger<uint32_t >(Attribute)
130- : hasProperty (Attribute);
131- MDOps.push_back (buildSpirvDecorMetadata (Ctx, DecorCode, DecorValue));
229+ MDNode *SPIRVMetadata = attributeToDecorateMetadata (Ctx, Attribute);
230+ if (SPIRVMetadata)
231+ MDOps.push_back (SPIRVMetadata);
132232 }
133233
134234 // Some properties should be handled specially.
@@ -154,6 +254,36 @@ PreservedAnalyses CompileTimePropertiesPass::run(Module &M,
154254 }
155255 }
156256
257+ // Process all properties on kernels.
258+ for (Function &F : M) {
259+ // Only consider kernels.
260+ if (F.getCallingConv () != CallingConv::SPIR_KERNEL)
261+ continue ;
262+
263+ SmallVector<Metadata *, 8 > MDOps;
264+ SmallVector<std::pair<std::string, MDNode *>, 8 > NamedMDOps;
265+ for (const Attribute &Attribute : F.getAttributes ().getFnAttrs ()) {
266+ if (MDNode *SPIRVMetadata = attributeToDecorateMetadata (Ctx, Attribute))
267+ MDOps.push_back (SPIRVMetadata);
268+ else if (auto NamedMetadata = attributeToExecModeMetadata (M, Attribute))
269+ NamedMDOps.push_back (*NamedMetadata);
270+ }
271+
272+ // Add the generated metadata to the kernel function.
273+ if (!MDOps.empty ()) {
274+ F.addMetadata (MDKindID, *MDNode::get (Ctx, MDOps));
275+ CompileTimePropertiesMet = true ;
276+ }
277+
278+ // Add the new named metadata to the kernel function.
279+ for (std::pair<std::string, MDNode *> NamedMD : NamedMDOps) {
280+ // If multiple sources defined this metadata, prioritize the existing one.
281+ if (F.hasMetadata (NamedMD.first ))
282+ continue ;
283+ F.addMetadata (NamedMD.first , *NamedMD.second );
284+ }
285+ }
286+
157287 // Check pointer annotations.
158288 SmallVector<IntrinsicInst *, 4 > RemovableAnnots;
159289 for (Function &F : M)
0 commit comments