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