clang 24.0.0git
CIRGenBuiltinRISCV.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 contains code to emit RISC-V Builtin calls as CIR or a function call
10// to be later resolved.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CIRGenFunction.h"
16
17using namespace clang;
18using namespace clang::CIRGen;
19
20std::optional<mlir::Value>
21CIRGenFunction::emitRISCVBuiltinExpr(unsigned builtinID, const CallExpr *e) {
22 if (builtinID == Builtin::BI__builtin_cpu_supports ||
23 builtinID == Builtin::BI__builtin_cpu_init ||
24 builtinID == Builtin::BI__builtin_cpu_is) {
25 cgm.errorNYI(e->getSourceRange(),
26 std::string("unimplemented RISC-V builtin call: ") +
27 getContext().BuiltinInfo.getName(builtinID));
28 return mlir::Value{};
29 }
30
31 StringRef intrinsicName;
32 mlir::Type returnType = convertType(e->getType());
34
35 // `iceArguments` is a bitmap indicating whether the argument at the i-th bit
36 // is required to be a constant integer expression.
37 unsigned iceArguments = 0;
39 getContext().GetBuiltinType(builtinID, error, &iceArguments);
40 assert(error == ASTContext::GE_None && "Should not codegen an error");
41
42 if (builtinID == RISCV::BI__builtin_riscv_ntl_load)
43 iceArguments |= (1 << 1);
44 if (builtinID == RISCV::BI__builtin_riscv_ntl_store)
45 iceArguments |= (1 << 2);
46
47 for (auto [idx, arg] : llvm::enumerate(e->arguments()))
48 ops.push_back(emitScalarOrConstFoldImmArg(iceArguments, idx, arg));
49
50 switch (builtinID) {
51 default:
52 llvm_unreachable("unexpected builtin ID");
53
54 // Zbb
55 case RISCV::BI__builtin_riscv_orc_b_32:
56 case RISCV::BI__builtin_riscv_orc_b_64: {
57 intrinsicName = "riscv.orc.b";
58 break;
59 }
60
61 // Zbc
62 case RISCV::BI__builtin_riscv_clmul_32:
63 case RISCV::BI__builtin_riscv_clmul_64: {
64 intrinsicName = "clmul";
65 break;
66 }
67 case RISCV::BI__builtin_riscv_clmulh_32:
68 case RISCV::BI__builtin_riscv_clmulh_64: {
69 intrinsicName = "riscv.clmulh";
70 break;
71 }
72 case RISCV::BI__builtin_riscv_clmulr_32:
73 case RISCV::BI__builtin_riscv_clmulr_64: {
74 intrinsicName = "riscv.clmulr";
75 break;
76 }
77
78 // Zbkx
79 case RISCV::BI__builtin_riscv_xperm4_32:
80 case RISCV::BI__builtin_riscv_xperm4_64: {
81 intrinsicName = "riscv.xperm4";
82 break;
83 }
84 case RISCV::BI__builtin_riscv_xperm8_32:
85 case RISCV::BI__builtin_riscv_xperm8_64: {
86 intrinsicName = "riscv.xperm8";
87 break;
88 }
89 // Zbkb
90 case RISCV::BI__builtin_riscv_brev8_32:
91 case RISCV::BI__builtin_riscv_brev8_64: {
92 intrinsicName = "riscv.brev8";
93 break;
94 }
95 case RISCV::BI__builtin_riscv_zip_32: {
96 intrinsicName = "riscv.zip";
97 break;
98 }
99 case RISCV::BI__builtin_riscv_unzip_32: {
100 intrinsicName = "riscv.unzip";
101 break;
102 }
103 // Zknd
104 case RISCV::BI__builtin_riscv_aes32dsi: {
105 intrinsicName = "riscv.aes32dsi";
106 break;
107 }
108 case RISCV::BI__builtin_riscv_aes32dsmi: {
109 intrinsicName = "riscv.aes32dsmi";
110 break;
111 }
112 case RISCV::BI__builtin_riscv_aes64ds: {
113 intrinsicName = "riscv.aes64ds";
114 break;
115 }
116 case RISCV::BI__builtin_riscv_aes64dsm: {
117 intrinsicName = "riscv.aes64dsm";
118 break;
119 }
120 case RISCV::BI__builtin_riscv_aes64im: {
121 intrinsicName = "riscv.aes64im";
122 break;
123 }
124 // Zknd & Zkne
125 case RISCV::BI__builtin_riscv_aes64ks1i:
126 case RISCV::BI__builtin_riscv_aes64ks2:
127 // Zkne
128 case RISCV::BI__builtin_riscv_aes32esi:
129 case RISCV::BI__builtin_riscv_aes32esmi:
130 case RISCV::BI__builtin_riscv_aes64es:
131 case RISCV::BI__builtin_riscv_aes64esm: {
132 cgm.errorNYI(e->getSourceRange(),
133 std::string("unimplemented RISC-V builtin call: ") +
134 getContext().BuiltinInfo.getName(builtinID));
135 return mlir::Value{};
136 }
137 case RISCV::BI__builtin_riscv_sha256sig0: {
138 intrinsicName = "riscv.sha256sig0";
139 break;
140 }
141 case RISCV::BI__builtin_riscv_sha256sig1: {
142 intrinsicName = "riscv.sha256sig1";
143 break;
144 }
145 case RISCV::BI__builtin_riscv_sha256sum0: {
146 intrinsicName = "riscv.sha256sum0";
147 break;
148 }
149 case RISCV::BI__builtin_riscv_sha256sum1: {
150 intrinsicName = "riscv.sha256sum1";
151 break;
152 }
153 case RISCV::BI__builtin_riscv_sha512sig0h:
154 case RISCV::BI__builtin_riscv_sha512sig0l:
155 case RISCV::BI__builtin_riscv_sha512sig1h:
156 case RISCV::BI__builtin_riscv_sha512sig1l:
157 case RISCV::BI__builtin_riscv_sha512sum0r:
158 case RISCV::BI__builtin_riscv_sha512sum1r:
159 case RISCV::BI__builtin_riscv_sha512sig0:
160 case RISCV::BI__builtin_riscv_sha512sig1:
161 case RISCV::BI__builtin_riscv_sha512sum0:
162 case RISCV::BI__builtin_riscv_sha512sum1: {
163 cgm.errorNYI(e->getSourceRange(),
164 std::string("unimplemented RISC-V builtin call: ") +
165 getContext().BuiltinInfo.getName(builtinID));
166 return mlir::Value{};
167 }
168 // Zksed
169 case RISCV::BI__builtin_riscv_sm4ks: {
170 intrinsicName = "riscv.sm4ks";
171 break;
172 }
173 case RISCV::BI__builtin_riscv_sm4ed: {
174 intrinsicName = "riscv.sm4ed";
175 break;
176 }
177 // Zksh
178 case RISCV::BI__builtin_riscv_sm3p0: {
179 intrinsicName = "riscv.sm3p0";
180 break;
181 }
182 case RISCV::BI__builtin_riscv_sm3p1: {
183 intrinsicName = "riscv.sm3p1";
184 break;
185 }
186 // Zbb
187 case RISCV::BI__builtin_riscv_clz_32:
188 case RISCV::BI__builtin_riscv_clz_64: {
189 mlir::Location loc = getLoc(e->getSourceRange());
190 auto op = cir::BitClzOp::create(builder, loc, ops[0],
191 /*poison_zero=*/false);
192 mlir::Value result = op.getResult();
193 if (result.getType() != returnType)
194 result = builder.createIntCast(result, returnType);
195 return result;
196 }
197 case RISCV::BI__builtin_riscv_ctz_32:
198 case RISCV::BI__builtin_riscv_ctz_64: {
199 mlir::Location loc = getLoc(e->getSourceRange());
200 auto op = cir::BitCtzOp::create(builder, loc, ops[0],
201 /*poison_zero=*/false);
202 mlir::Value result = op.getResult();
203 if (result.getType() != returnType)
204 result = builder.createIntCast(result, returnType);
205 return result;
206 }
207
208 // Zihintntl
209 case RISCV::BI__builtin_riscv_ntl_load:
210 case RISCV::BI__builtin_riscv_ntl_store: {
211 unsigned domainVal = 5; // Default __RISCV_NTLH_ALL
212 unsigned domainArgNo =
213 builtinID == RISCV::BI__builtin_riscv_ntl_load ? 1 : 2;
214 if (e->getNumArgs() > domainArgNo) {
215 const std::optional<llvm::APSInt> result =
216 e->getArg(domainArgNo)->getIntegerConstantExpr(getContext());
217 assert(result && "Expected NTLH domain argument to be a constant");
218 domainVal = result->getZExtValue();
219 }
220
221 mlir::Location loc = getLoc(e->getSourceRange());
222 mlir::Attribute domainAttr = builder.getI32IntegerAttr(domainVal);
223 Address addr(ops[0],
224 cgm.getNaturalPointeeTypeAlignment(e->getArg(0)->getType()));
225 if (builtinID == RISCV::BI__builtin_riscv_ntl_load) {
226 auto load = builder.createLoad(loc, addr, /*isVolatile=*/false,
227 /*isNontemporal=*/true);
228 load->setAttr("cir.riscv_nontemporal_domain", domainAttr);
229 return load.getResult();
230 }
231
232 mlir::Value val = emitToMemory(ops[1], e->getArg(1)->getType());
233 auto store = builder.createStore(loc, val, addr, /*isVolatile=*/false,
234 /*isNontemporal=*/true);
235 store->setAttr("cir.riscv_nontemporal_domain", domainAttr);
236 return mlir::Value{};
237 }
238
239 // Zihintpause
240 case RISCV::BI__builtin_riscv_pause: {
241 intrinsicName = "riscv.pause";
242 returnType = builder.getVoidTy();
243 break;
244 }
245
246 // XCValu
247 case RISCV::BI__builtin_riscv_cv_alu_addN: {
248 intrinsicName = "riscv.cv.alu.addN";
249 break;
250 }
251 case RISCV::BI__builtin_riscv_cv_alu_addRN: {
252 intrinsicName = "riscv.cv.alu.addRN";
253 break;
254 }
255 case RISCV::BI__builtin_riscv_cv_alu_adduN: {
256 intrinsicName = "riscv.cv.alu.adduN";
257 break;
258 }
259 case RISCV::BI__builtin_riscv_cv_alu_adduRN: {
260 intrinsicName = "riscv.cv.alu.adduRN";
261 break;
262 }
263 case RISCV::BI__builtin_riscv_cv_alu_clip: {
264 intrinsicName = "riscv.cv.alu.clip";
265 break;
266 }
267 case RISCV::BI__builtin_riscv_cv_alu_clipu: {
268 intrinsicName = "riscv.cv.alu.clipu";
269 break;
270 }
271 case RISCV::BI__builtin_riscv_cv_alu_extbs: {
272 mlir::Value result = builder.createIntCast(ops[0], builder.getSInt8Ty());
273 return builder.createIntCast(result, returnType);
274 }
275 case RISCV::BI__builtin_riscv_cv_alu_extbz: {
276 mlir::Value result = builder.createIntCast(ops[0], builder.getUInt8Ty());
277 return builder.createIntCast(result, returnType);
278 }
279 case RISCV::BI__builtin_riscv_cv_alu_exths: {
280 mlir::Value result = builder.createIntCast(ops[0], builder.getSInt16Ty());
281 return builder.createIntCast(result, returnType);
282 }
283 case RISCV::BI__builtin_riscv_cv_alu_exthz: {
284 mlir::Value result = builder.createIntCast(ops[0], builder.getUInt16Ty());
285 return builder.createIntCast(result, returnType);
286 }
287 case RISCV::BI__builtin_riscv_cv_alu_sle: {
288 mlir::Location loc = getLoc(e->getSourceRange());
289 mlir::Value result =
290 builder.createCompare(loc, cir::CmpOpKind::le, ops[0], ops[1]);
291 return builder.createBoolToInt(result, returnType);
292 }
293 case RISCV::BI__builtin_riscv_cv_alu_sleu: {
294 mlir::Location loc = getLoc(e->getSourceRange());
295 mlir::Value result =
296 builder.createCompare(loc, cir::CmpOpKind::le, ops[0], ops[1]);
297 return builder.createBoolToInt(result, returnType);
298 }
299 case RISCV::BI__builtin_riscv_cv_alu_subN: {
300 intrinsicName = "riscv.cv.alu.subN";
301 break;
302 }
303 case RISCV::BI__builtin_riscv_cv_alu_subRN: {
304 intrinsicName = "riscv.cv.alu.subRN";
305 break;
306 }
307 case RISCV::BI__builtin_riscv_cv_alu_subuN: {
308 intrinsicName = "riscv.cv.alu.subuN";
309 break;
310 }
311 case RISCV::BI__builtin_riscv_cv_alu_subuRN: {
312 intrinsicName = "riscv.cv.alu.subuRN";
313 break;
314 }
315 // XAndesPerf
316 case RISCV::BI__builtin_riscv_nds_ffb_32:
317 case RISCV::BI__builtin_riscv_nds_ffb_64: {
318 intrinsicName = "riscv.nds.ffb";
319 break;
320 }
321 case RISCV::BI__builtin_riscv_nds_ffzmism_32:
322 case RISCV::BI__builtin_riscv_nds_ffzmism_64: {
323 intrinsicName = "riscv.nds.ffzmism";
324 break;
325 }
326 case RISCV::BI__builtin_riscv_nds_ffmism_32:
327 case RISCV::BI__builtin_riscv_nds_ffmism_64: {
328 intrinsicName = "riscv.nds.ffmism";
329 break;
330 }
331 case RISCV::BI__builtin_riscv_nds_flmism_32:
332 case RISCV::BI__builtin_riscv_nds_flmism_64: {
333 intrinsicName = "riscv.nds.flmism";
334 break;
335 }
336 // XAndesBFHCvt
337 case RISCV::BI__builtin_riscv_nds_fcvt_s_bf16:
338 case RISCV::BI__builtin_riscv_nds_fcvt_bf16_s: {
339 cgm.errorNYI(e->getSourceRange(),
340 std::string("unimplemented RISC-V builtin call: ") +
341 getContext().BuiltinInfo.getName(builtinID));
342 return mlir::Value{};
343 }
344
345 // XMIPS execution control
346 case RISCV::BI__builtin_riscv_mips_pause:
347 case RISCV::BI__builtin_riscv_mips_ehb:
348 case RISCV::BI__builtin_riscv_mips_ihb: {
349 cgm.errorNYI(e->getSourceRange(),
350 std::string("unimplemented RISC-V builtin call: ") +
351 getContext().BuiltinInfo.getName(builtinID));
352 return mlir::Value{};
353 }
354
355 // TODO: Handle vector builtins in tablegen.
356 }
357
358 mlir::Location loc = getLoc(e->getSourceRange());
359 return builder.emitIntrinsicCallOp(loc, intrinsicName, returnType, ops);
360}
Enumerates target-specific builtins in their own namespaces within namespace clang.
QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error, unsigned *IntegerConstantArgs=nullptr) const
Return the type for the specified builtin.
@ GE_None
No error.
mlir::Type convertType(clang::QualType t)
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
std::optional< mlir::Value > emitRISCVBuiltinExpr(unsigned builtinID, const CallExpr *expr)
mlir::Value emitToMemory(mlir::Value value, clang::QualType ty)
Given a value and its clang type, returns the value casted to its memory representation.
clang::ASTContext & getContext() const
mlir::Value emitScalarOrConstFoldImmArg(unsigned iceArguments, unsigned idx, const Expr *argExpr)
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2987
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3191
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3178
arg_range arguments()
Definition Expr.h:3239
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx, bool AllowRelaxedEval=false) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
QualType getType() const
Definition Expr.h:145
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
Top level wrappers for InstallAPI frontend operations.