/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/utils/TableGen/RISCVVEmitter.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang -----===// |
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 | | // |
9 | | // This tablegen backend is responsible for emitting riscv_vector.h which |
10 | | // includes a declaration and definition of each intrinsic functions specified |
11 | | // in https://github.com/riscv/rvv-intrinsic-doc. |
12 | | // |
13 | | // See also the documentation in include/clang/Basic/riscv_vector.td. |
14 | | // |
15 | | //===----------------------------------------------------------------------===// |
16 | | |
17 | | #include "clang/Support/RISCVVIntrinsicUtils.h" |
18 | | #include "llvm/ADT/ArrayRef.h" |
19 | | #include "llvm/ADT/SmallSet.h" |
20 | | #include "llvm/ADT/StringExtras.h" |
21 | | #include "llvm/ADT/StringMap.h" |
22 | | #include "llvm/ADT/StringSet.h" |
23 | | #include "llvm/ADT/Twine.h" |
24 | | #include "llvm/TableGen/Error.h" |
25 | | #include "llvm/TableGen/Record.h" |
26 | | #include <numeric> |
27 | | |
28 | | using namespace llvm; |
29 | | using namespace clang::RISCV; |
30 | | |
31 | | namespace { |
32 | | class RVVEmitter { |
33 | | private: |
34 | | RecordKeeper &Records; |
35 | | // Concat BasicType, LMUL and Proto as key |
36 | | StringMap<RVVType> LegalTypes; |
37 | | StringSet<> IllegalTypes; |
38 | | |
39 | | public: |
40 | 0 | RVVEmitter(RecordKeeper &R) : Records(R) {} |
41 | | |
42 | | /// Emit riscv_vector.h |
43 | | void createHeader(raw_ostream &o); |
44 | | |
45 | | /// Emit all the __builtin prototypes and code needed by Sema. |
46 | | void createBuiltins(raw_ostream &o); |
47 | | |
48 | | /// Emit all the information needed to map builtin -> LLVM IR intrinsic. |
49 | | void createCodeGen(raw_ostream &o); |
50 | | |
51 | | std::string getSuffixStr(char Type, int Log2LMUL, StringRef Prototypes); |
52 | | |
53 | | private: |
54 | | /// Create all intrinsics and add them to \p Out |
55 | | void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out); |
56 | | /// Print HeaderCode in RVVHeader Record to \p Out |
57 | | void printHeaderCode(raw_ostream &OS); |
58 | | /// Compute output and input types by applying different config (basic type |
59 | | /// and LMUL with type transformers). It also record result of type in legal |
60 | | /// or illegal set to avoid compute the same config again. The result maybe |
61 | | /// have illegal RVVType. |
62 | | Optional<RVVTypes> computeTypes(BasicType BT, int Log2LMUL, unsigned NF, |
63 | | ArrayRef<std::string> PrototypeSeq); |
64 | | Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, StringRef Proto); |
65 | | |
66 | | /// Emit Acrh predecessor definitions and body, assume the element of Defs are |
67 | | /// sorted by extension. |
68 | | void emitArchMacroAndBody( |
69 | | std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o, |
70 | | std::function<void(raw_ostream &, const RVVIntrinsic &)>); |
71 | | |
72 | | // Emit the architecture preprocessor definitions. Return true when emits |
73 | | // non-empty string. |
74 | | bool emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, |
75 | | raw_ostream &o); |
76 | | // Slice Prototypes string into sub prototype string and process each sub |
77 | | // prototype string individually in the Handler. |
78 | | void parsePrototypes(StringRef Prototypes, |
79 | | std::function<void(StringRef)> Handler); |
80 | | }; |
81 | | |
82 | | } // namespace |
83 | | |
84 | 0 | void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { |
85 | 0 | if (!RVVI->getIRName().empty()) |
86 | 0 | OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; |
87 | 0 | if (RVVI->getNF() >= 2) |
88 | 0 | OS << " NF = " + utostr(RVVI->getNF()) + ";\n"; |
89 | 0 | if (RVVI->hasManualCodegen()) { |
90 | 0 | OS << RVVI->getManualCodegen(); |
91 | 0 | OS << "break;\n"; |
92 | 0 | return; |
93 | 0 | } |
94 | | |
95 | 0 | if (RVVI->isMasked()) { |
96 | 0 | if (RVVI->hasVL()) { |
97 | 0 | OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; |
98 | 0 | if (RVVI->hasPolicyOperand()) |
99 | 0 | OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," |
100 | 0 | " TAIL_UNDISTURBED));\n"; |
101 | 0 | } else { |
102 | 0 | OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; |
103 | 0 | } |
104 | 0 | } else { |
105 | 0 | if (RVVI->hasPolicyOperand()) |
106 | 0 | OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " |
107 | 0 | "TAIL_UNDISTURBED));\n"; |
108 | 0 | else if (RVVI->hasPassthruOperand()) { |
109 | 0 | OS << " Ops.push_back(llvm::UndefValue::get(ResultType));\n"; |
110 | 0 | OS << " std::rotate(Ops.rbegin(), Ops.rbegin() + 1, Ops.rend());\n"; |
111 | 0 | } |
112 | 0 | } |
113 | |
|
114 | 0 | OS << " IntrinsicTypes = {"; |
115 | 0 | ListSeparator LS; |
116 | 0 | for (const auto &Idx : RVVI->getIntrinsicTypes()) { |
117 | 0 | if (Idx == -1) |
118 | 0 | OS << LS << "ResultType"; |
119 | 0 | else |
120 | 0 | OS << LS << "Ops[" << Idx << "]->getType()"; |
121 | 0 | } |
122 | | |
123 | | // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is |
124 | | // always last operand. |
125 | 0 | if (RVVI->hasVL()) |
126 | 0 | OS << ", Ops.back()->getType()"; |
127 | 0 | OS << "};\n"; |
128 | 0 | OS << " break;\n"; |
129 | 0 | } |
130 | | |
131 | 0 | void emitIntrinsicFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) { |
132 | 0 | OS << "__attribute__((__clang_builtin_alias__("; |
133 | 0 | OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n"; |
134 | 0 | OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getName() << "("; |
135 | | // Emit function arguments |
136 | 0 | const RVVTypes &InputTypes = RVVI.getInputTypes(); |
137 | 0 | if (!InputTypes.empty()) { |
138 | 0 | ListSeparator LS; |
139 | 0 | for (unsigned i = 0; i < InputTypes.size(); ++i) |
140 | 0 | OS << LS << InputTypes[i]->getTypeStr(); |
141 | 0 | } |
142 | 0 | OS << ");\n"; |
143 | 0 | } |
144 | | |
145 | 0 | void emitMangledFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) { |
146 | 0 | OS << "__attribute__((__clang_builtin_alias__("; |
147 | 0 | OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n"; |
148 | 0 | OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getMangledName() |
149 | 0 | << "("; |
150 | | // Emit function arguments |
151 | 0 | const RVVTypes &InputTypes = RVVI.getInputTypes(); |
152 | 0 | if (!InputTypes.empty()) { |
153 | 0 | ListSeparator LS; |
154 | 0 | for (unsigned i = 0; i < InputTypes.size(); ++i) |
155 | 0 | OS << LS << InputTypes[i]->getTypeStr(); |
156 | 0 | } |
157 | 0 | OS << ");\n"; |
158 | 0 | } |
159 | | |
160 | | //===----------------------------------------------------------------------===// |
161 | | // RVVEmitter implementation |
162 | | //===----------------------------------------------------------------------===// |
163 | 0 | void RVVEmitter::createHeader(raw_ostream &OS) { |
164 | |
|
165 | 0 | OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " |
166 | 0 | "-------------------===\n" |
167 | 0 | " *\n" |
168 | 0 | " *\n" |
169 | 0 | " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " |
170 | 0 | "Exceptions.\n" |
171 | 0 | " * See https://llvm.org/LICENSE.txt for license information.\n" |
172 | 0 | " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" |
173 | 0 | " *\n" |
174 | 0 | " *===-----------------------------------------------------------------" |
175 | 0 | "------===\n" |
176 | 0 | " */\n\n"; |
177 | |
|
178 | 0 | OS << "#ifndef __RISCV_VECTOR_H\n"; |
179 | 0 | OS << "#define __RISCV_VECTOR_H\n\n"; |
180 | |
|
181 | 0 | OS << "#include <stdint.h>\n"; |
182 | 0 | OS << "#include <stddef.h>\n\n"; |
183 | |
|
184 | 0 | OS << "#ifndef __riscv_vector\n"; |
185 | 0 | OS << "#error \"Vector intrinsics require the vector extension.\"\n"; |
186 | 0 | OS << "#endif\n\n"; |
187 | |
|
188 | 0 | OS << "#ifdef __cplusplus\n"; |
189 | 0 | OS << "extern \"C\" {\n"; |
190 | 0 | OS << "#endif\n\n"; |
191 | |
|
192 | 0 | printHeaderCode(OS); |
193 | |
|
194 | 0 | std::vector<std::unique_ptr<RVVIntrinsic>> Defs; |
195 | 0 | createRVVIntrinsics(Defs); |
196 | |
|
197 | 0 | auto printType = [&](auto T) { |
198 | 0 | OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() |
199 | 0 | << ";\n"; |
200 | 0 | }; |
201 | |
|
202 | 0 | constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; |
203 | | // Print RVV boolean types. |
204 | 0 | for (int Log2LMUL : Log2LMULs) { |
205 | 0 | auto T = computeType('c', Log2LMUL, "m"); |
206 | 0 | if (T.hasValue()) |
207 | 0 | printType(T.getValue()); |
208 | 0 | } |
209 | | // Print RVV int/float types. |
210 | 0 | for (char I : StringRef("csil")) { |
211 | 0 | for (int Log2LMUL : Log2LMULs) { |
212 | 0 | auto T = computeType(I, Log2LMUL, "v"); |
213 | 0 | if (T.hasValue()) { |
214 | 0 | printType(T.getValue()); |
215 | 0 | auto UT = computeType(I, Log2LMUL, "Uv"); |
216 | 0 | printType(UT.getValue()); |
217 | 0 | } |
218 | 0 | } |
219 | 0 | } |
220 | 0 | OS << "#if defined(__riscv_zvfh)\n"; |
221 | 0 | for (int Log2LMUL : Log2LMULs) { |
222 | 0 | auto T = computeType('x', Log2LMUL, "v"); |
223 | 0 | if (T.hasValue()) |
224 | 0 | printType(T.getValue()); |
225 | 0 | } |
226 | 0 | OS << "#endif\n"; |
227 | |
|
228 | 0 | OS << "#if defined(__riscv_f)\n"; |
229 | 0 | for (int Log2LMUL : Log2LMULs) { |
230 | 0 | auto T = computeType('f', Log2LMUL, "v"); |
231 | 0 | if (T.hasValue()) |
232 | 0 | printType(T.getValue()); |
233 | 0 | } |
234 | 0 | OS << "#endif\n"; |
235 | |
|
236 | 0 | OS << "#if defined(__riscv_d)\n"; |
237 | 0 | for (int Log2LMUL : Log2LMULs) { |
238 | 0 | auto T = computeType('d', Log2LMUL, "v"); |
239 | 0 | if (T.hasValue()) |
240 | 0 | printType(T.getValue()); |
241 | 0 | } |
242 | 0 | OS << "#endif\n\n"; |
243 | | |
244 | | // The same extension include in the same arch guard marco. |
245 | 0 | llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, |
246 | 0 | const std::unique_ptr<RVVIntrinsic> &B) { |
247 | 0 | return A->getRISCVPredefinedMacros() < B->getRISCVPredefinedMacros(); |
248 | 0 | }); |
249 | |
|
250 | 0 | OS << "#define __rvv_ai static __inline__\n"; |
251 | | |
252 | | // Print intrinsic functions with macro |
253 | 0 | emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { |
254 | 0 | OS << "__rvv_ai "; |
255 | 0 | emitIntrinsicFuncDef(Inst, OS); |
256 | 0 | }); |
257 | |
|
258 | 0 | OS << "#undef __rvv_ai\n\n"; |
259 | |
|
260 | 0 | OS << "#define __riscv_v_intrinsic_overloading 1\n"; |
261 | | |
262 | | // Print Overloaded APIs |
263 | 0 | OS << "#define __rvv_aio static __inline__ " |
264 | 0 | "__attribute__((__overloadable__))\n"; |
265 | |
|
266 | 0 | emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { |
267 | 0 | if (!Inst.isMasked() && !Inst.hasUnMaskedOverloaded()) |
268 | 0 | return; |
269 | 0 | OS << "__rvv_aio "; |
270 | 0 | emitMangledFuncDef(Inst, OS); |
271 | 0 | }); |
272 | |
|
273 | 0 | OS << "#undef __rvv_aio\n"; |
274 | |
|
275 | 0 | OS << "\n#ifdef __cplusplus\n"; |
276 | 0 | OS << "}\n"; |
277 | 0 | OS << "#endif // __cplusplus\n"; |
278 | 0 | OS << "#endif // __RISCV_VECTOR_H\n"; |
279 | 0 | } |
280 | | |
281 | 0 | void RVVEmitter::createBuiltins(raw_ostream &OS) { |
282 | 0 | std::vector<std::unique_ptr<RVVIntrinsic>> Defs; |
283 | 0 | createRVVIntrinsics(Defs); |
284 | | |
285 | | // Map to keep track of which builtin names have already been emitted. |
286 | 0 | StringMap<RVVIntrinsic *> BuiltinMap; |
287 | |
|
288 | 0 | OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; |
289 | 0 | OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " |
290 | 0 | "ATTRS, \"zve32x\")\n"; |
291 | 0 | OS << "#endif\n"; |
292 | 0 | for (auto &Def : Defs) { |
293 | 0 | auto P = |
294 | 0 | BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); |
295 | 0 | if (!P.second) { |
296 | | // Verf that this would have produced the same builtin definition. |
297 | 0 | if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias()) |
298 | 0 | PrintFatalError("Builtin with same name has different hasAutoDef"); |
299 | 0 | else if (!Def->hasBuiltinAlias() && |
300 | 0 | P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr()) |
301 | 0 | PrintFatalError("Builtin with same name has different type string"); |
302 | 0 | continue; |
303 | 0 | } |
304 | 0 | OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; |
305 | 0 | if (!Def->hasBuiltinAlias()) |
306 | 0 | OS << Def->getBuiltinTypeStr(); |
307 | 0 | OS << "\", \"n\")\n"; |
308 | 0 | } |
309 | 0 | OS << "#undef RISCVV_BUILTIN\n"; |
310 | 0 | } |
311 | | |
312 | 0 | void RVVEmitter::createCodeGen(raw_ostream &OS) { |
313 | 0 | std::vector<std::unique_ptr<RVVIntrinsic>> Defs; |
314 | 0 | createRVVIntrinsics(Defs); |
315 | | // IR name could be empty, use the stable sort preserves the relative order. |
316 | 0 | llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, |
317 | 0 | const std::unique_ptr<RVVIntrinsic> &B) { |
318 | 0 | return A->getIRName() < B->getIRName(); |
319 | 0 | }); |
320 | | |
321 | | // Map to keep track of which builtin names have already been emitted. |
322 | 0 | StringMap<RVVIntrinsic *> BuiltinMap; |
323 | | |
324 | | // Print switch body when the ir name or ManualCodegen changes from previous |
325 | | // iteration. |
326 | 0 | RVVIntrinsic *PrevDef = Defs.begin()->get(); |
327 | 0 | for (auto &Def : Defs) { |
328 | 0 | StringRef CurIRName = Def->getIRName(); |
329 | 0 | if (CurIRName != PrevDef->getIRName() || |
330 | 0 | (Def->getManualCodegen() != PrevDef->getManualCodegen())) { |
331 | 0 | emitCodeGenSwitchBody(PrevDef, OS); |
332 | 0 | } |
333 | 0 | PrevDef = Def.get(); |
334 | |
|
335 | 0 | auto P = |
336 | 0 | BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); |
337 | 0 | if (P.second) { |
338 | 0 | OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() |
339 | 0 | << ":\n"; |
340 | 0 | continue; |
341 | 0 | } |
342 | | |
343 | 0 | if (P.first->second->getIRName() != Def->getIRName()) |
344 | 0 | PrintFatalError("Builtin with same name has different IRName"); |
345 | 0 | else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) |
346 | 0 | PrintFatalError("Builtin with same name has different ManualCodegen"); |
347 | 0 | else if (P.first->second->getNF() != Def->getNF()) |
348 | 0 | PrintFatalError("Builtin with same name has different NF"); |
349 | 0 | else if (P.first->second->isMasked() != Def->isMasked()) |
350 | 0 | PrintFatalError("Builtin with same name has different isMasked"); |
351 | 0 | else if (P.first->second->hasVL() != Def->hasVL()) |
352 | 0 | PrintFatalError("Builtin with same name has different hasVL"); |
353 | 0 | else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme()) |
354 | 0 | PrintFatalError("Builtin with same name has different getPolicyScheme"); |
355 | 0 | else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) |
356 | 0 | PrintFatalError("Builtin with same name has different IntrinsicTypes"); |
357 | 0 | } |
358 | 0 | emitCodeGenSwitchBody(Defs.back().get(), OS); |
359 | 0 | OS << "\n"; |
360 | 0 | } |
361 | | |
362 | | void RVVEmitter::parsePrototypes(StringRef Prototypes, |
363 | 0 | std::function<void(StringRef)> Handler) { |
364 | 0 | const StringRef Primaries("evwqom0ztul"); |
365 | 0 | while (!Prototypes.empty()) { |
366 | 0 | size_t Idx = 0; |
367 | | // Skip over complex prototype because it could contain primitive type |
368 | | // character. |
369 | 0 | if (Prototypes[0] == '(') |
370 | 0 | Idx = Prototypes.find_first_of(')'); |
371 | 0 | Idx = Prototypes.find_first_of(Primaries, Idx); |
372 | 0 | assert(Idx != StringRef::npos); |
373 | 0 | Handler(Prototypes.slice(0, Idx + 1)); |
374 | 0 | Prototypes = Prototypes.drop_front(Idx + 1); |
375 | 0 | } |
376 | 0 | } |
377 | | |
378 | | std::string RVVEmitter::getSuffixStr(char Type, int Log2LMUL, |
379 | 0 | StringRef Prototypes) { |
380 | 0 | SmallVector<std::string> SuffixStrs; |
381 | 0 | parsePrototypes(Prototypes, [&](StringRef Proto) { |
382 | 0 | auto T = computeType(Type, Log2LMUL, Proto); |
383 | 0 | SuffixStrs.push_back(T.getValue()->getShortStr()); |
384 | 0 | }); |
385 | 0 | return join(SuffixStrs, "_"); |
386 | 0 | } |
387 | | |
388 | | void RVVEmitter::createRVVIntrinsics( |
389 | 0 | std::vector<std::unique_ptr<RVVIntrinsic>> &Out) { |
390 | 0 | std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); |
391 | 0 | for (auto *R : RV) { |
392 | 0 | StringRef Name = R->getValueAsString("Name"); |
393 | 0 | StringRef SuffixProto = R->getValueAsString("Suffix"); |
394 | 0 | StringRef MangledName = R->getValueAsString("MangledName"); |
395 | 0 | StringRef MangledSuffixProto = R->getValueAsString("MangledSuffix"); |
396 | 0 | StringRef Prototypes = R->getValueAsString("Prototype"); |
397 | 0 | StringRef TypeRange = R->getValueAsString("TypeRange"); |
398 | 0 | bool HasMasked = R->getValueAsBit("HasMasked"); |
399 | 0 | bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); |
400 | 0 | bool HasVL = R->getValueAsBit("HasVL"); |
401 | 0 | Record *MaskedPolicyRecord = R->getValueAsDef("MaskedPolicy"); |
402 | 0 | PolicyScheme MaskedPolicy = |
403 | 0 | static_cast<PolicyScheme>(MaskedPolicyRecord->getValueAsInt("Value")); |
404 | 0 | Record *UnMaskedPolicyRecord = R->getValueAsDef("UnMaskedPolicy"); |
405 | 0 | PolicyScheme UnMaskedPolicy = |
406 | 0 | static_cast<PolicyScheme>(UnMaskedPolicyRecord->getValueAsInt("Value")); |
407 | 0 | bool HasUnMaskedOverloaded = R->getValueAsBit("HasUnMaskedOverloaded"); |
408 | 0 | std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); |
409 | 0 | bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias"); |
410 | 0 | StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); |
411 | 0 | StringRef MaskedManualCodegen = R->getValueAsString("MaskedManualCodegen"); |
412 | 0 | std::vector<int64_t> IntrinsicTypes = |
413 | 0 | R->getValueAsListOfInts("IntrinsicTypes"); |
414 | 0 | std::vector<StringRef> RequiredFeatures = |
415 | 0 | R->getValueAsListOfStrings("RequiredFeatures"); |
416 | 0 | StringRef IRName = R->getValueAsString("IRName"); |
417 | 0 | StringRef MaskedIRName = R->getValueAsString("MaskedIRName"); |
418 | 0 | unsigned NF = R->getValueAsInt("NF"); |
419 | | |
420 | | // Parse prototype and create a list of primitive type with transformers |
421 | | // (operand) in ProtoSeq. ProtoSeq[0] is output operand. |
422 | 0 | SmallVector<std::string> ProtoSeq; |
423 | 0 | parsePrototypes(Prototypes, [&ProtoSeq](StringRef Proto) { |
424 | 0 | ProtoSeq.push_back(Proto.str()); |
425 | 0 | }); |
426 | | |
427 | | // Compute Builtin types |
428 | 0 | SmallVector<std::string> ProtoMaskSeq = ProtoSeq; |
429 | 0 | if (HasMasked) { |
430 | | // If HasMaskedOffOperand, insert result type as first input operand. |
431 | 0 | if (HasMaskedOffOperand) { |
432 | 0 | if (NF == 1) { |
433 | 0 | ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]); |
434 | 0 | } else { |
435 | | // Convert |
436 | | // (void, op0 address, op1 address, ...) |
437 | | // to |
438 | | // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) |
439 | 0 | for (unsigned I = 0; I < NF; ++I) |
440 | 0 | ProtoMaskSeq.insert( |
441 | 0 | ProtoMaskSeq.begin() + NF + 1, |
442 | 0 | ProtoSeq[1].substr(1)); // Use substr(1) to skip '*' |
443 | 0 | } |
444 | 0 | } |
445 | 0 | if (HasMaskedOffOperand && NF > 1) { |
446 | | // Convert |
447 | | // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) |
448 | | // to |
449 | | // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1, |
450 | | // ...) |
451 | 0 | ProtoMaskSeq.insert(ProtoMaskSeq.begin() + NF + 1, "m"); |
452 | 0 | } else { |
453 | | // If HasMasked, insert 'm' as first input operand. |
454 | 0 | ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, "m"); |
455 | 0 | } |
456 | 0 | } |
457 | | // If HasVL, append 'z' to last operand |
458 | 0 | if (HasVL) { |
459 | 0 | ProtoSeq.push_back("z"); |
460 | 0 | ProtoMaskSeq.push_back("z"); |
461 | 0 | } |
462 | | |
463 | | // Create Intrinsics for each type and LMUL. |
464 | 0 | for (char I : TypeRange) { |
465 | 0 | for (int Log2LMUL : Log2LMULList) { |
466 | 0 | Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, NF, ProtoSeq); |
467 | | // Ignored to create new intrinsic if there are any illegal types. |
468 | 0 | if (!Types.hasValue()) |
469 | 0 | continue; |
470 | | |
471 | 0 | auto SuffixStr = getSuffixStr(I, Log2LMUL, SuffixProto); |
472 | 0 | auto MangledSuffixStr = getSuffixStr(I, Log2LMUL, MangledSuffixProto); |
473 | | // Create a unmasked intrinsic |
474 | 0 | Out.push_back(std::make_unique<RVVIntrinsic>( |
475 | 0 | Name, SuffixStr, MangledName, MangledSuffixStr, IRName, |
476 | 0 | /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL, |
477 | 0 | UnMaskedPolicy, HasUnMaskedOverloaded, HasBuiltinAlias, |
478 | 0 | ManualCodegen, Types.getValue(), IntrinsicTypes, RequiredFeatures, |
479 | 0 | NF)); |
480 | 0 | if (HasMasked) { |
481 | | // Create a masked intrinsic |
482 | 0 | Optional<RVVTypes> MaskTypes = |
483 | 0 | computeTypes(I, Log2LMUL, NF, ProtoMaskSeq); |
484 | 0 | Out.push_back(std::make_unique<RVVIntrinsic>( |
485 | 0 | Name, SuffixStr, MangledName, MangledSuffixStr, MaskedIRName, |
486 | 0 | /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicy, |
487 | 0 | HasUnMaskedOverloaded, HasBuiltinAlias, MaskedManualCodegen, |
488 | 0 | MaskTypes.getValue(), IntrinsicTypes, RequiredFeatures, NF)); |
489 | 0 | } |
490 | 0 | } // end for Log2LMULList |
491 | 0 | } // end for TypeRange |
492 | 0 | } |
493 | 0 | } |
494 | | |
495 | 0 | void RVVEmitter::printHeaderCode(raw_ostream &OS) { |
496 | 0 | std::vector<Record *> RVVHeaders = |
497 | 0 | Records.getAllDerivedDefinitions("RVVHeader"); |
498 | 0 | for (auto *R : RVVHeaders) { |
499 | 0 | StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); |
500 | 0 | OS << HeaderCodeStr.str(); |
501 | 0 | } |
502 | 0 | } |
503 | | |
504 | | Optional<RVVTypes> |
505 | | RVVEmitter::computeTypes(BasicType BT, int Log2LMUL, unsigned NF, |
506 | 0 | ArrayRef<std::string> PrototypeSeq) { |
507 | | // LMUL x NF must be less than or equal to 8. |
508 | 0 | if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8) |
509 | 0 | return llvm::None; |
510 | | |
511 | 0 | RVVTypes Types; |
512 | 0 | for (const std::string &Proto : PrototypeSeq) { |
513 | 0 | auto T = computeType(BT, Log2LMUL, Proto); |
514 | 0 | if (!T.hasValue()) |
515 | 0 | return llvm::None; |
516 | | // Record legal type index |
517 | 0 | Types.push_back(T.getValue()); |
518 | 0 | } |
519 | 0 | return Types; |
520 | 0 | } |
521 | | |
522 | | Optional<RVVTypePtr> RVVEmitter::computeType(BasicType BT, int Log2LMUL, |
523 | 0 | StringRef Proto) { |
524 | 0 | std::string Idx = Twine(Twine(BT) + Twine(Log2LMUL) + Proto).str(); |
525 | | // Search first |
526 | 0 | auto It = LegalTypes.find(Idx); |
527 | 0 | if (It != LegalTypes.end()) |
528 | 0 | return &(It->second); |
529 | 0 | if (IllegalTypes.count(Idx)) |
530 | 0 | return llvm::None; |
531 | | // Compute type and record the result. |
532 | 0 | RVVType T(BT, Log2LMUL, Proto); |
533 | 0 | if (T.isValid()) { |
534 | | // Record legal type index and value. |
535 | 0 | LegalTypes.insert({Idx, T}); |
536 | 0 | return &(LegalTypes[Idx]); |
537 | 0 | } |
538 | | // Record illegal type index. |
539 | 0 | IllegalTypes.insert(Idx); |
540 | 0 | return llvm::None; |
541 | 0 | } |
542 | | |
543 | | void RVVEmitter::emitArchMacroAndBody( |
544 | | std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS, |
545 | 0 | std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) { |
546 | 0 | RISCVPredefinedMacroT PrevMacros = |
547 | 0 | (*Defs.begin())->getRISCVPredefinedMacros(); |
548 | 0 | bool NeedEndif = emitMacroRestrictionStr(PrevMacros, OS); |
549 | 0 | for (auto &Def : Defs) { |
550 | 0 | RISCVPredefinedMacroT CurMacros = Def->getRISCVPredefinedMacros(); |
551 | 0 | if (CurMacros != PrevMacros) { |
552 | 0 | if (NeedEndif) |
553 | 0 | OS << "#endif\n\n"; |
554 | 0 | NeedEndif = emitMacroRestrictionStr(CurMacros, OS); |
555 | 0 | PrevMacros = CurMacros; |
556 | 0 | } |
557 | 0 | if (Def->hasBuiltinAlias()) |
558 | 0 | PrintBody(OS, *Def); |
559 | 0 | } |
560 | 0 | if (NeedEndif) |
561 | 0 | OS << "#endif\n\n"; |
562 | 0 | } |
563 | | |
564 | | bool RVVEmitter::emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, |
565 | 0 | raw_ostream &OS) { |
566 | 0 | if (PredefinedMacros == RISCVPredefinedMacro::Basic) |
567 | 0 | return false; |
568 | 0 | OS << "#if "; |
569 | 0 | ListSeparator LS(" && "); |
570 | 0 | if (PredefinedMacros & RISCVPredefinedMacro::V) |
571 | 0 | OS << LS << "defined(__riscv_v)"; |
572 | 0 | if (PredefinedMacros & RISCVPredefinedMacro::Zvfh) |
573 | 0 | OS << LS << "defined(__riscv_zvfh)"; |
574 | 0 | if (PredefinedMacros & RISCVPredefinedMacro::RV64) |
575 | 0 | OS << LS << "(__riscv_xlen == 64)"; |
576 | 0 | if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64) |
577 | 0 | OS << LS << "(__riscv_v_elen >= 64)"; |
578 | 0 | if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp32) |
579 | 0 | OS << LS << "(__riscv_v_elen_fp >= 32)"; |
580 | 0 | if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp64) |
581 | 0 | OS << LS << "(__riscv_v_elen_fp >= 64)"; |
582 | 0 | OS << "\n"; |
583 | 0 | return true; |
584 | 0 | } |
585 | | |
586 | | namespace clang { |
587 | 0 | void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { |
588 | 0 | RVVEmitter(Records).createHeader(OS); |
589 | 0 | } |
590 | | |
591 | 0 | void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { |
592 | 0 | RVVEmitter(Records).createBuiltins(OS); |
593 | 0 | } |
594 | | |
595 | 0 | void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { |
596 | 0 | RVVEmitter(Records).createCodeGen(OS); |
597 | 0 | } |
598 | | |
599 | | } // End namespace clang |