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 case RISCV::BI__builtin_riscv_aes32dsmi:
106 case RISCV::BI__builtin_riscv_aes64ds:
107 case RISCV::BI__builtin_riscv_aes64dsm:
108 case RISCV::BI__builtin_riscv_aes64im:
109 // Zknd & Zkne
110 case RISCV::BI__builtin_riscv_aes64ks1i:
111 case RISCV::BI__builtin_riscv_aes64ks2:
112 // Zkne
113 case RISCV::BI__builtin_riscv_aes32esi:
114 case RISCV::BI__builtin_riscv_aes32esmi:
115 case RISCV::BI__builtin_riscv_aes64es:
116 case RISCV::BI__builtin_riscv_aes64esm: {
117 cgm.errorNYI(e->getSourceRange(),
118 std::string("unimplemented RISC-V builtin call: ") +
119 getContext().BuiltinInfo.getName(builtinID));
120 return mlir::Value{};
121 }
122 case RISCV::BI__builtin_riscv_sha256sig0: {
123 intrinsicName = "riscv.sha256sig0";
124 break;
125 }
126 case RISCV::BI__builtin_riscv_sha256sig1: {
127 intrinsicName = "riscv.sha256sig1";
128 break;
129 }
130 case RISCV::BI__builtin_riscv_sha256sum0: {
131 intrinsicName = "riscv.sha256sum0";
132 break;
133 }
134 case RISCV::BI__builtin_riscv_sha256sum1: {
135 intrinsicName = "riscv.sha256sum1";
136 break;
137 }
138 case RISCV::BI__builtin_riscv_sha512sig0h:
139 case RISCV::BI__builtin_riscv_sha512sig0l:
140 case RISCV::BI__builtin_riscv_sha512sig1h:
141 case RISCV::BI__builtin_riscv_sha512sig1l:
142 case RISCV::BI__builtin_riscv_sha512sum0r:
143 case RISCV::BI__builtin_riscv_sha512sum1r:
144 case RISCV::BI__builtin_riscv_sha512sig0:
145 case RISCV::BI__builtin_riscv_sha512sig1:
146 case RISCV::BI__builtin_riscv_sha512sum0:
147 case RISCV::BI__builtin_riscv_sha512sum1: {
148 cgm.errorNYI(e->getSourceRange(),
149 std::string("unimplemented RISC-V builtin call: ") +
150 getContext().BuiltinInfo.getName(builtinID));
151 return mlir::Value{};
152 }
153 // Zksed
154 case RISCV::BI__builtin_riscv_sm4ks: {
155 intrinsicName = "riscv.sm4ks";
156 break;
157 }
158 case RISCV::BI__builtin_riscv_sm4ed: {
159 intrinsicName = "riscv.sm4ed";
160 break;
161 }
162 // Zksh
163 case RISCV::BI__builtin_riscv_sm3p0: {
164 intrinsicName = "riscv.sm3p0";
165 break;
166 }
167 case RISCV::BI__builtin_riscv_sm3p1: {
168 intrinsicName = "riscv.sm3p1";
169 break;
170 }
171 // Zbb
172 case RISCV::BI__builtin_riscv_clz_32:
173 case RISCV::BI__builtin_riscv_clz_64: {
174 mlir::Location loc = getLoc(e->getSourceRange());
175 auto op = cir::BitClzOp::create(builder, loc, ops[0],
176 /*poison_zero=*/false);
177 mlir::Value result = op.getResult();
178 if (result.getType() != returnType)
179 result = builder.createIntCast(result, returnType);
180 return result;
181 }
182 case RISCV::BI__builtin_riscv_ctz_32:
183 case RISCV::BI__builtin_riscv_ctz_64: {
184 mlir::Location loc = getLoc(e->getSourceRange());
185 auto op = cir::BitCtzOp::create(builder, loc, ops[0],
186 /*poison_zero=*/false);
187 mlir::Value result = op.getResult();
188 if (result.getType() != returnType)
189 result = builder.createIntCast(result, returnType);
190 return result;
191 }
192
193 // Zihintntl
194 case RISCV::BI__builtin_riscv_ntl_load:
195 case RISCV::BI__builtin_riscv_ntl_store: {
196 unsigned domainVal = 5; // Default __RISCV_NTLH_ALL
197 unsigned domainArgNo =
198 builtinID == RISCV::BI__builtin_riscv_ntl_load ? 1 : 2;
199 if (e->getNumArgs() > domainArgNo) {
200 const std::optional<llvm::APSInt> result =
201 e->getArg(domainArgNo)->getIntegerConstantExpr(getContext());
202 assert(result && "Expected NTLH domain argument to be a constant");
203 domainVal = result->getZExtValue();
204 }
205
206 mlir::Location loc = getLoc(e->getSourceRange());
207 mlir::Attribute domainAttr = builder.getI32IntegerAttr(domainVal);
208 Address addr(ops[0],
209 cgm.getNaturalPointeeTypeAlignment(e->getArg(0)->getType()));
210 if (builtinID == RISCV::BI__builtin_riscv_ntl_load) {
211 auto load = builder.createLoad(loc, addr, /*isVolatile=*/false,
212 /*isNontemporal=*/true);
213 load->setAttr("cir.riscv_nontemporal_domain", domainAttr);
214 return load.getResult();
215 }
216
217 mlir::Value val = emitToMemory(ops[1], e->getArg(1)->getType());
218 auto store = builder.createStore(loc, val, addr, /*isVolatile=*/false,
219 /*isNontemporal=*/true);
220 store->setAttr("cir.riscv_nontemporal_domain", domainAttr);
221 return mlir::Value{};
222 }
223
224 // Zihintpause
225 case RISCV::BI__builtin_riscv_pause: {
226 intrinsicName = "riscv.pause";
227 returnType = builder.getVoidTy();
228 break;
229 }
230
231 // XCValu
232 case RISCV::BI__builtin_riscv_cv_alu_addN: {
233 intrinsicName = "riscv.cv.alu.addN";
234 break;
235 }
236 case RISCV::BI__builtin_riscv_cv_alu_addRN: {
237 intrinsicName = "riscv.cv.alu.addRN";
238 break;
239 }
240 case RISCV::BI__builtin_riscv_cv_alu_adduN: {
241 intrinsicName = "riscv.cv.alu.adduN";
242 break;
243 }
244 case RISCV::BI__builtin_riscv_cv_alu_adduRN: {
245 intrinsicName = "riscv.cv.alu.adduRN";
246 break;
247 }
248 case RISCV::BI__builtin_riscv_cv_alu_clip: {
249 intrinsicName = "riscv.cv.alu.clip";
250 break;
251 }
252 case RISCV::BI__builtin_riscv_cv_alu_clipu: {
253 intrinsicName = "riscv.cv.alu.clipu";
254 break;
255 }
256 case RISCV::BI__builtin_riscv_cv_alu_extbs: {
257 mlir::Value result = builder.createIntCast(ops[0], builder.getSInt8Ty());
258 return builder.createIntCast(result, returnType);
259 }
260 case RISCV::BI__builtin_riscv_cv_alu_extbz: {
261 mlir::Value result = builder.createIntCast(ops[0], builder.getUInt8Ty());
262 return builder.createIntCast(result, returnType);
263 }
264 case RISCV::BI__builtin_riscv_cv_alu_exths: {
265 mlir::Value result = builder.createIntCast(ops[0], builder.getSInt16Ty());
266 return builder.createIntCast(result, returnType);
267 }
268 case RISCV::BI__builtin_riscv_cv_alu_exthz: {
269 mlir::Value result = builder.createIntCast(ops[0], builder.getUInt16Ty());
270 return builder.createIntCast(result, returnType);
271 }
272 case RISCV::BI__builtin_riscv_cv_alu_sle: {
273 mlir::Location loc = getLoc(e->getSourceRange());
274 mlir::Value result =
275 builder.createCompare(loc, cir::CmpOpKind::le, ops[0], ops[1]);
276 return builder.createBoolToInt(result, returnType);
277 }
278 case RISCV::BI__builtin_riscv_cv_alu_sleu: {
279 mlir::Location loc = getLoc(e->getSourceRange());
280 mlir::Value result =
281 builder.createCompare(loc, cir::CmpOpKind::le, ops[0], ops[1]);
282 return builder.createBoolToInt(result, returnType);
283 }
284 case RISCV::BI__builtin_riscv_cv_alu_subN: {
285 intrinsicName = "riscv.cv.alu.subN";
286 break;
287 }
288 case RISCV::BI__builtin_riscv_cv_alu_subRN: {
289 intrinsicName = "riscv.cv.alu.subRN";
290 break;
291 }
292 case RISCV::BI__builtin_riscv_cv_alu_subuN: {
293 intrinsicName = "riscv.cv.alu.subuN";
294 break;
295 }
296 case RISCV::BI__builtin_riscv_cv_alu_subuRN: {
297 intrinsicName = "riscv.cv.alu.subuRN";
298 break;
299 }
300 // XAndesPerf
301 case RISCV::BI__builtin_riscv_nds_ffb_32:
302 case RISCV::BI__builtin_riscv_nds_ffb_64:
303 case RISCV::BI__builtin_riscv_nds_ffzmism_32:
304 case RISCV::BI__builtin_riscv_nds_ffzmism_64:
305 case RISCV::BI__builtin_riscv_nds_ffmism_32:
306 case RISCV::BI__builtin_riscv_nds_ffmism_64:
307 case RISCV::BI__builtin_riscv_nds_flmism_32:
308 case RISCV::BI__builtin_riscv_nds_flmism_64:
309 // XAndesBFHCvt
310 case RISCV::BI__builtin_riscv_nds_fcvt_s_bf16:
311 case RISCV::BI__builtin_riscv_nds_fcvt_bf16_s: {
312 cgm.errorNYI(e->getSourceRange(),
313 std::string("unimplemented RISC-V builtin call: ") +
314 getContext().BuiltinInfo.getName(builtinID));
315 return mlir::Value{};
316 }
317
318 // XMIPS execution control
319 case RISCV::BI__builtin_riscv_mips_pause:
320 case RISCV::BI__builtin_riscv_mips_ehb:
321 case RISCV::BI__builtin_riscv_mips_ihb: {
322 cgm.errorNYI(e->getSourceRange(),
323 std::string("unimplemented RISC-V builtin call: ") +
324 getContext().BuiltinInfo.getName(builtinID));
325 return mlir::Value{};
326 }
327
328 // TODO: Handle vector builtins in tablegen.
329 }
330
331 mlir::Location loc = getLoc(e->getSourceRange());
332 return builder.emitIntrinsicCallOp(loc, intrinsicName, returnType, ops);
333}
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:2949
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3153
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3140
arg_range arguments()
Definition Expr.h:3201
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
QualType getType() const
Definition Expr.h:144
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
The JSON file list parser is used to communicate input to InstallAPI.