1//===-------- RISCV.cpp - Emit LLVM Code for builtins ---------------------===//
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 Builtin calls as LLVM code.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CodeGenFunction.h"
14#include "clang/Basic/TargetBuiltins.h"
15#include "llvm/IR/IntrinsicsRISCV.h"
16#include "llvm/TargetParser/RISCVISAInfo.h"
17#include "llvm/TargetParser/RISCVTargetParser.h"
18
19using namespace clang;
20using namespace CodeGen;
21using namespace llvm;
22
23Value *CodeGenFunction::EmitRISCVCpuInit() {
24 llvm::FunctionType *FTy = llvm::FunctionType::get(Result: VoidTy, Params: {VoidPtrTy}, isVarArg: false);
25 llvm::FunctionCallee Func =
26 CGM.CreateRuntimeFunction(Ty: FTy, Name: "__init_riscv_feature_bits");
27 auto *CalleeGV = cast<llvm::GlobalValue>(Val: Func.getCallee());
28 CalleeGV->setDSOLocal(true);
29 CalleeGV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
30 return Builder.CreateCall(Callee: Func, Args: {llvm::ConstantPointerNull::get(T: VoidPtrTy)});
31}
32
33Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {
34
35 const Expr *FeatureExpr = E->getArg(Arg: 0)->IgnoreParenCasts();
36 StringRef FeatureStr = cast<StringLiteral>(Val: FeatureExpr)->getString();
37 if (!getContext().getTargetInfo().validateCpuSupports(Name: FeatureStr))
38 return Builder.getFalse();
39
40 return EmitRISCVCpuSupports(FeaturesStrs: ArrayRef<StringRef>(FeatureStr));
41}
42
43static Value *loadRISCVFeatureBits(unsigned Index, CGBuilderTy &Builder,
44 CodeGenModule &CGM) {
45 llvm::Type *Int32Ty = Builder.getInt32Ty();
46 llvm::Type *Int64Ty = Builder.getInt64Ty();
47 llvm::ArrayType *ArrayOfInt64Ty =
48 llvm::ArrayType::get(ElementType: Int64Ty, NumElements: llvm::RISCVISAInfo::FeatureBitSize);
49 llvm::Type *StructTy = llvm::StructType::get(elt1: Int32Ty, elts: ArrayOfInt64Ty);
50 llvm::Constant *RISCVFeaturesBits =
51 CGM.CreateRuntimeVariable(Ty: StructTy, Name: "__riscv_feature_bits");
52 cast<llvm::GlobalValue>(Val: RISCVFeaturesBits)->setDSOLocal(true);
53 Value *IndexVal = llvm::ConstantInt::get(Ty: Int32Ty, V: Index);
54 llvm::Value *GEPIndices[] = {Builder.getInt32(C: 0), Builder.getInt32(C: 1),
55 IndexVal};
56 Value *Ptr =
57 Builder.CreateInBoundsGEP(Ty: StructTy, Ptr: RISCVFeaturesBits, IdxList: GEPIndices);
58 Value *FeaturesBit =
59 Builder.CreateAlignedLoad(Ty: Int64Ty, Addr: Ptr, Align: CharUnits::fromQuantity(Quantity: 8));
60 return FeaturesBit;
61}
62
63Value *CodeGenFunction::EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs) {
64 const unsigned RISCVFeatureLength = llvm::RISCVISAInfo::FeatureBitSize;
65 uint64_t RequireBitMasks[RISCVFeatureLength] = {0};
66
67 for (auto Feat : FeaturesStrs) {
68 auto [GroupID, BitPos] = RISCVISAInfo::getRISCVFeaturesBitsInfo(Ext: Feat);
69
70 // If there isn't BitPos for this feature, skip this version.
71 // It also report the warning to user during compilation.
72 if (BitPos == -1)
73 return Builder.getFalse();
74
75 RequireBitMasks[GroupID] |= (1ULL << BitPos);
76 }
77
78 Value *Result = nullptr;
79 for (unsigned Idx = 0; Idx < RISCVFeatureLength; Idx++) {
80 if (RequireBitMasks[Idx] == 0)
81 continue;
82
83 Value *Mask = Builder.getInt64(C: RequireBitMasks[Idx]);
84 Value *Bitset =
85 Builder.CreateAnd(LHS: loadRISCVFeatureBits(Index: Idx, Builder, CGM), RHS: Mask);
86 Value *CmpV = Builder.CreateICmpEQ(LHS: Bitset, RHS: Mask);
87 Result = (!Result) ? CmpV : Builder.CreateAnd(LHS: Result, RHS: CmpV);
88 }
89
90 assert(Result && "Should have value here.");
91
92 return Result;
93}
94
95Value *CodeGenFunction::EmitRISCVCpuIs(const CallExpr *E) {
96 const Expr *CPUExpr = E->getArg(Arg: 0)->IgnoreParenCasts();
97 StringRef CPUStr = cast<clang::StringLiteral>(Val: CPUExpr)->getString();
98 return EmitRISCVCpuIs(CPUStr);
99}
100
101Value *CodeGenFunction::EmitRISCVCpuIs(StringRef CPUStr) {
102 llvm::Type *Int32Ty = Builder.getInt32Ty();
103 llvm::Type *Int64Ty = Builder.getInt64Ty();
104 llvm::StructType *StructTy = llvm::StructType::get(elt1: Int32Ty, elts: Int64Ty, elts: Int64Ty);
105 llvm::Constant *RISCVCPUModel =
106 CGM.CreateRuntimeVariable(Ty: StructTy, Name: "__riscv_cpu_model");
107 cast<llvm::GlobalValue>(Val: RISCVCPUModel)->setDSOLocal(true);
108
109 auto loadRISCVCPUID = [&](unsigned Index) {
110 Value *Ptr = Builder.CreateStructGEP(Ty: StructTy, Ptr: RISCVCPUModel, Idx: Index);
111 Value *CPUID = Builder.CreateAlignedLoad(Ty: StructTy->getTypeAtIndex(N: Index),
112 Ptr, Align: llvm::MaybeAlign());
113 return CPUID;
114 };
115
116 const llvm::RISCV::CPUModel Model = llvm::RISCV::getCPUModel(CPU: CPUStr);
117
118 // Compare mvendorid.
119 Value *VendorID = loadRISCVCPUID(0);
120 Value *Result =
121 Builder.CreateICmpEQ(LHS: VendorID, RHS: Builder.getInt32(C: Model.MVendorID));
122
123 // Compare marchid.
124 Value *ArchID = loadRISCVCPUID(1);
125 Result = Builder.CreateAnd(
126 LHS: Result, RHS: Builder.CreateICmpEQ(LHS: ArchID, RHS: Builder.getInt64(C: Model.MArchID)));
127
128 // Compare mimpid.
129 Value *ImpID = loadRISCVCPUID(2);
130 Result = Builder.CreateAnd(
131 LHS: Result, RHS: Builder.CreateICmpEQ(LHS: ImpID, RHS: Builder.getInt64(C: Model.MImpID)));
132
133 return Result;
134}
135
136Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
137 const CallExpr *E,
138 ReturnValueSlot ReturnValue) {
139
140 if (BuiltinID == Builtin::BI__builtin_cpu_supports)
141 return EmitRISCVCpuSupports(E);
142 if (BuiltinID == Builtin::BI__builtin_cpu_init)
143 return EmitRISCVCpuInit();
144 if (BuiltinID == Builtin::BI__builtin_cpu_is)
145 return EmitRISCVCpuIs(E);
146
147 SmallVector<Value *, 4> Ops;
148 llvm::Type *ResultType = ConvertType(T: E->getType());
149
150 // Find out if any arguments are required to be integer constant expressions.
151 unsigned ICEArguments = 0;
152 ASTContext::GetBuiltinTypeError Error;
153 getContext().GetBuiltinType(ID: BuiltinID, Error, IntegerConstantArgs: &ICEArguments);
154 if (Error == ASTContext::GE_Missing_type) {
155 // Vector intrinsics don't have a type string.
156 assert(BuiltinID >= clang::RISCV::FirstRVVBuiltin &&
157 BuiltinID <= clang::RISCV::LastRVVBuiltin);
158 ICEArguments = 0;
159 if (BuiltinID == RISCVVector::BI__builtin_rvv_vget_v ||
160 BuiltinID == RISCVVector::BI__builtin_rvv_vset_v)
161 ICEArguments = 1 << 1;
162 } else {
163 assert(Error == ASTContext::GE_None && "Unexpected error");
164 }
165
166 if (BuiltinID == RISCV::BI__builtin_riscv_ntl_load)
167 ICEArguments |= (1 << 1);
168 if (BuiltinID == RISCV::BI__builtin_riscv_ntl_store)
169 ICEArguments |= (1 << 2);
170
171 for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) {
172 // Handle aggregate argument, namely RVV tuple types in segment load/store
173 if (hasAggregateEvaluationKind(T: E->getArg(Arg: i)->getType())) {
174 LValue L = EmitAggExprToLValue(E: E->getArg(Arg: i));
175 llvm::Value *AggValue = Builder.CreateLoad(Addr: L.getAddress());
176 Ops.push_back(Elt: AggValue);
177 continue;
178 }
179 Ops.push_back(Elt: EmitScalarOrConstFoldImmArg(ICEArguments, Idx: i, E));
180 }
181
182 Intrinsic::ID ID = Intrinsic::not_intrinsic;
183 // The 0th bit simulates the `vta` of RVV
184 // The 1st bit simulates the `vma` of RVV
185 constexpr unsigned RVV_VTA = 0x1;
186 constexpr unsigned RVV_VMA = 0x2;
187 int PolicyAttrs = 0;
188 bool IsMasked = false;
189 // This is used by segment load/store to determine it's llvm type.
190 unsigned SegInstSEW = 8;
191
192 // Required for overloaded intrinsics.
193 llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes;
194 switch (BuiltinID) {
195 default: llvm_unreachable("unexpected builtin ID");
196 case RISCV::BI__builtin_riscv_orc_b_32:
197 case RISCV::BI__builtin_riscv_orc_b_64:
198 case RISCV::BI__builtin_riscv_clmul_32:
199 case RISCV::BI__builtin_riscv_clmul_64:
200 case RISCV::BI__builtin_riscv_clmulh_32:
201 case RISCV::BI__builtin_riscv_clmulh_64:
202 case RISCV::BI__builtin_riscv_clmulr_32:
203 case RISCV::BI__builtin_riscv_clmulr_64:
204 case RISCV::BI__builtin_riscv_xperm4_32:
205 case RISCV::BI__builtin_riscv_xperm4_64:
206 case RISCV::BI__builtin_riscv_xperm8_32:
207 case RISCV::BI__builtin_riscv_xperm8_64:
208 case RISCV::BI__builtin_riscv_brev8_32:
209 case RISCV::BI__builtin_riscv_brev8_64:
210 case RISCV::BI__builtin_riscv_zip_32:
211 case RISCV::BI__builtin_riscv_unzip_32: {
212 switch (BuiltinID) {
213 default: llvm_unreachable("unexpected builtin ID");
214 // Zbb
215 case RISCV::BI__builtin_riscv_orc_b_32:
216 case RISCV::BI__builtin_riscv_orc_b_64:
217 ID = Intrinsic::riscv_orc_b;
218 break;
219
220 // Zbc
221 case RISCV::BI__builtin_riscv_clmul_32:
222 case RISCV::BI__builtin_riscv_clmul_64:
223 ID = Intrinsic::riscv_clmul;
224 break;
225 case RISCV::BI__builtin_riscv_clmulh_32:
226 case RISCV::BI__builtin_riscv_clmulh_64:
227 ID = Intrinsic::riscv_clmulh;
228 break;
229 case RISCV::BI__builtin_riscv_clmulr_32:
230 case RISCV::BI__builtin_riscv_clmulr_64:
231 ID = Intrinsic::riscv_clmulr;
232 break;
233
234 // Zbkx
235 case RISCV::BI__builtin_riscv_xperm8_32:
236 case RISCV::BI__builtin_riscv_xperm8_64:
237 ID = Intrinsic::riscv_xperm8;
238 break;
239 case RISCV::BI__builtin_riscv_xperm4_32:
240 case RISCV::BI__builtin_riscv_xperm4_64:
241 ID = Intrinsic::riscv_xperm4;
242 break;
243
244 // Zbkb
245 case RISCV::BI__builtin_riscv_brev8_32:
246 case RISCV::BI__builtin_riscv_brev8_64:
247 ID = Intrinsic::riscv_brev8;
248 break;
249 case RISCV::BI__builtin_riscv_zip_32:
250 ID = Intrinsic::riscv_zip;
251 break;
252 case RISCV::BI__builtin_riscv_unzip_32:
253 ID = Intrinsic::riscv_unzip;
254 break;
255 }
256
257 IntrinsicTypes = {ResultType};
258 break;
259 }
260
261 // Zk builtins
262
263 // Zknh
264 case RISCV::BI__builtin_riscv_sha256sig0:
265 ID = Intrinsic::riscv_sha256sig0;
266 break;
267 case RISCV::BI__builtin_riscv_sha256sig1:
268 ID = Intrinsic::riscv_sha256sig1;
269 break;
270 case RISCV::BI__builtin_riscv_sha256sum0:
271 ID = Intrinsic::riscv_sha256sum0;
272 break;
273 case RISCV::BI__builtin_riscv_sha256sum1:
274 ID = Intrinsic::riscv_sha256sum1;
275 break;
276
277 // Zksed
278 case RISCV::BI__builtin_riscv_sm4ks:
279 ID = Intrinsic::riscv_sm4ks;
280 break;
281 case RISCV::BI__builtin_riscv_sm4ed:
282 ID = Intrinsic::riscv_sm4ed;
283 break;
284
285 // Zksh
286 case RISCV::BI__builtin_riscv_sm3p0:
287 ID = Intrinsic::riscv_sm3p0;
288 break;
289 case RISCV::BI__builtin_riscv_sm3p1:
290 ID = Intrinsic::riscv_sm3p1;
291 break;
292
293 case RISCV::BI__builtin_riscv_clz_32:
294 case RISCV::BI__builtin_riscv_clz_64: {
295 Function *F = CGM.getIntrinsic(IID: Intrinsic::ctlz, Tys: Ops[0]->getType());
296 Value *Result = Builder.CreateCall(Callee: F, Args: {Ops[0], Builder.getInt1(V: false)});
297 if (Result->getType() != ResultType)
298 Result =
299 Builder.CreateIntCast(V: Result, DestTy: ResultType, /*isSigned*/ false, Name: "cast");
300 return Result;
301 }
302 case RISCV::BI__builtin_riscv_ctz_32:
303 case RISCV::BI__builtin_riscv_ctz_64: {
304 Function *F = CGM.getIntrinsic(IID: Intrinsic::cttz, Tys: Ops[0]->getType());
305 Value *Result = Builder.CreateCall(Callee: F, Args: {Ops[0], Builder.getInt1(V: false)});
306 if (Result->getType() != ResultType)
307 Result =
308 Builder.CreateIntCast(V: Result, DestTy: ResultType, /*isSigned*/ false, Name: "cast");
309 return Result;
310 }
311
312 // Zihintntl
313 case RISCV::BI__builtin_riscv_ntl_load: {
314 llvm::Type *ResTy = ConvertType(T: E->getType());
315 unsigned DomainVal = 5; // Default __RISCV_NTLH_ALL
316 if (Ops.size() == 2)
317 DomainVal = cast<ConstantInt>(Val: Ops[1])->getZExtValue();
318
319 llvm::MDNode *RISCVDomainNode = llvm::MDNode::get(
320 Context&: getLLVMContext(),
321 MDs: llvm::ConstantAsMetadata::get(C: Builder.getInt32(C: DomainVal)));
322 llvm::MDNode *NontemporalNode = llvm::MDNode::get(
323 Context&: getLLVMContext(), MDs: llvm::ConstantAsMetadata::get(C: Builder.getInt32(C: 1)));
324
325 int Width;
326 if(ResTy->isScalableTy()) {
327 const ScalableVectorType *SVTy = cast<ScalableVectorType>(Val: ResTy);
328 llvm::Type *ScalarTy = ResTy->getScalarType();
329 Width = ScalarTy->getPrimitiveSizeInBits() *
330 SVTy->getElementCount().getKnownMinValue();
331 } else
332 Width = ResTy->getPrimitiveSizeInBits();
333 LoadInst *Load = Builder.CreateLoad(
334 Addr: Address(Ops[0], ResTy, CharUnits::fromQuantity(Quantity: Width / 8)));
335
336 Load->setMetadata(KindID: llvm::LLVMContext::MD_nontemporal, Node: NontemporalNode);
337 Load->setMetadata(KindID: CGM.getModule().getMDKindID(Name: "riscv-nontemporal-domain"),
338 Node: RISCVDomainNode);
339
340 return Load;
341 }
342 case RISCV::BI__builtin_riscv_ntl_store: {
343 unsigned DomainVal = 5; // Default __RISCV_NTLH_ALL
344 if (Ops.size() == 3)
345 DomainVal = cast<ConstantInt>(Val: Ops[2])->getZExtValue();
346
347 llvm::MDNode *RISCVDomainNode = llvm::MDNode::get(
348 Context&: getLLVMContext(),
349 MDs: llvm::ConstantAsMetadata::get(C: Builder.getInt32(C: DomainVal)));
350 llvm::MDNode *NontemporalNode = llvm::MDNode::get(
351 Context&: getLLVMContext(), MDs: llvm::ConstantAsMetadata::get(C: Builder.getInt32(C: 1)));
352
353 StoreInst *Store = Builder.CreateDefaultAlignedStore(Val: Ops[1], Addr: Ops[0]);
354 Store->setMetadata(KindID: llvm::LLVMContext::MD_nontemporal, Node: NontemporalNode);
355 Store->setMetadata(KindID: CGM.getModule().getMDKindID(Name: "riscv-nontemporal-domain"),
356 Node: RISCVDomainNode);
357
358 return Store;
359 }
360 // Zihintpause
361 case RISCV::BI__builtin_riscv_pause: {
362 llvm::Function *Fn = CGM.getIntrinsic(IID: llvm::Intrinsic::riscv_pause);
363 return Builder.CreateCall(Callee: Fn, Args: {});
364 }
365
366 // XCValu
367 case RISCV::BI__builtin_riscv_cv_alu_addN:
368 ID = Intrinsic::riscv_cv_alu_addN;
369 break;
370 case RISCV::BI__builtin_riscv_cv_alu_addRN:
371 ID = Intrinsic::riscv_cv_alu_addRN;
372 break;
373 case RISCV::BI__builtin_riscv_cv_alu_adduN:
374 ID = Intrinsic::riscv_cv_alu_adduN;
375 break;
376 case RISCV::BI__builtin_riscv_cv_alu_adduRN:
377 ID = Intrinsic::riscv_cv_alu_adduRN;
378 break;
379 case RISCV::BI__builtin_riscv_cv_alu_clip:
380 ID = Intrinsic::riscv_cv_alu_clip;
381 break;
382 case RISCV::BI__builtin_riscv_cv_alu_clipu:
383 ID = Intrinsic::riscv_cv_alu_clipu;
384 break;
385 case RISCV::BI__builtin_riscv_cv_alu_extbs:
386 return Builder.CreateSExt(V: Builder.CreateTrunc(V: Ops[0], DestTy: Int8Ty), DestTy: Int32Ty,
387 Name: "extbs");
388 case RISCV::BI__builtin_riscv_cv_alu_extbz:
389 return Builder.CreateZExt(V: Builder.CreateTrunc(V: Ops[0], DestTy: Int8Ty), DestTy: Int32Ty,
390 Name: "extbz");
391 case RISCV::BI__builtin_riscv_cv_alu_exths:
392 return Builder.CreateSExt(V: Builder.CreateTrunc(V: Ops[0], DestTy: Int16Ty), DestTy: Int32Ty,
393 Name: "exths");
394 case RISCV::BI__builtin_riscv_cv_alu_exthz:
395 return Builder.CreateZExt(V: Builder.CreateTrunc(V: Ops[0], DestTy: Int16Ty), DestTy: Int32Ty,
396 Name: "exthz");
397 case RISCV::BI__builtin_riscv_cv_alu_sle:
398 return Builder.CreateZExt(V: Builder.CreateICmpSLE(LHS: Ops[0], RHS: Ops[1]), DestTy: Int32Ty,
399 Name: "sle");
400 case RISCV::BI__builtin_riscv_cv_alu_sleu:
401 return Builder.CreateZExt(V: Builder.CreateICmpULE(LHS: Ops[0], RHS: Ops[1]), DestTy: Int32Ty,
402 Name: "sleu");
403 case RISCV::BI__builtin_riscv_cv_alu_subN:
404 ID = Intrinsic::riscv_cv_alu_subN;
405 break;
406 case RISCV::BI__builtin_riscv_cv_alu_subRN:
407 ID = Intrinsic::riscv_cv_alu_subRN;
408 break;
409 case RISCV::BI__builtin_riscv_cv_alu_subuN:
410 ID = Intrinsic::riscv_cv_alu_subuN;
411 break;
412 case RISCV::BI__builtin_riscv_cv_alu_subuRN:
413 ID = Intrinsic::riscv_cv_alu_subuRN;
414 break;
415
416 // Vector builtins are handled from here.
417#include "clang/Basic/riscv_vector_builtin_cg.inc"
418
419 // SiFive Vector builtins are handled from here.
420#include "clang/Basic/riscv_sifive_vector_builtin_cg.inc"
421
422 // Andes Vector builtins are handled from here.
423#include "clang/Basic/riscv_andes_vector_builtin_cg.inc"
424 }
425
426 assert(ID != Intrinsic::not_intrinsic);
427
428 llvm::Function *F = CGM.getIntrinsic(IID: ID, Tys: IntrinsicTypes);
429 return Builder.CreateCall(Callee: F, Args: Ops, Name: "");
430}
431