xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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 
19 using namespace clang;
20 using namespace CodeGen;
21 using namespace llvm;
22 
23 Value *CodeGenFunction::EmitRISCVCpuInit() {
24   llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, {VoidPtrTy}, false);
25   llvm::FunctionCallee Func =
26       CGM.CreateRuntimeFunction(FTy, "__init_riscv_feature_bits");
27   auto *CalleeGV = cast<llvm::GlobalValue>(Func.getCallee());
28   CalleeGV->setDSOLocal(true);
29   CalleeGV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
30   return Builder.CreateCall(Func, {llvm::ConstantPointerNull::get(VoidPtrTy)});
31 }
32 
33 Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {
34 
35   const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
36   StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
37   if (!getContext().getTargetInfo().validateCpuSupports(FeatureStr))
38     return Builder.getFalse();
39 
40   return EmitRISCVCpuSupports(ArrayRef<StringRef>(FeatureStr));
41 }
42 
43 static 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(Int64Ty, llvm::RISCVISAInfo::FeatureBitSize);
49   llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
50   llvm::Constant *RISCVFeaturesBits =
51       CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
52   cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal(true);
53   Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
54   llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
55                                IndexVal};
56   Value *Ptr =
57       Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
58   Value *FeaturesBit =
59       Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
60   return FeaturesBit;
61 }
62 
63 Value *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(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(RequireBitMasks[Idx]);
84     Value *Bitset =
85         Builder.CreateAnd(loadRISCVFeatureBits(Idx, Builder, CGM), Mask);
86     Value *CmpV = Builder.CreateICmpEQ(Bitset, Mask);
87     Result = (!Result) ? CmpV : Builder.CreateAnd(Result, CmpV);
88   }
89 
90   assert(Result && "Should have value here.");
91 
92   return Result;
93 }
94 
95 Value *CodeGenFunction::EmitRISCVCpuIs(const CallExpr *E) {
96   const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
97   StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
98   return EmitRISCVCpuIs(CPUStr);
99 }
100 
101 Value *CodeGenFunction::EmitRISCVCpuIs(StringRef CPUStr) {
102   llvm::Type *Int32Ty = Builder.getInt32Ty();
103   llvm::Type *Int64Ty = Builder.getInt64Ty();
104   llvm::StructType *StructTy = llvm::StructType::get(Int32Ty, Int64Ty, Int64Ty);
105   llvm::Constant *RISCVCPUModel =
106       CGM.CreateRuntimeVariable(StructTy, "__riscv_cpu_model");
107   cast<llvm::GlobalValue>(RISCVCPUModel)->setDSOLocal(true);
108 
109   auto loadRISCVCPUID = [&](unsigned Index) {
110     Value *Ptr = Builder.CreateStructGEP(StructTy, RISCVCPUModel, Index);
111     Value *CPUID = Builder.CreateAlignedLoad(StructTy->getTypeAtIndex(Index),
112                                              Ptr, llvm::MaybeAlign());
113     return CPUID;
114   };
115 
116   const llvm::RISCV::CPUModel Model = llvm::RISCV::getCPUModel(CPUStr);
117 
118   // Compare mvendorid.
119   Value *VendorID = loadRISCVCPUID(0);
120   Value *Result =
121       Builder.CreateICmpEQ(VendorID, Builder.getInt32(Model.MVendorID));
122 
123   // Compare marchid.
124   Value *ArchID = loadRISCVCPUID(1);
125   Result = Builder.CreateAnd(
126       Result, Builder.CreateICmpEQ(ArchID, Builder.getInt64(Model.MArchID)));
127 
128   // Compare mimpid.
129   Value *ImpID = loadRISCVCPUID(2);
130   Result = Builder.CreateAnd(
131       Result, Builder.CreateICmpEQ(ImpID, Builder.getInt64(Model.MImpID)));
132 
133   return Result;
134 }
135 
136 Value *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(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(BuiltinID, Error, &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(E->getArg(i)->getType())) {
174       LValue L = EmitAggExprToLValue(E->getArg(i));
175       llvm::Value *AggValue = Builder.CreateLoad(L.getAddress());
176       Ops.push_back(AggValue);
177       continue;
178     }
179     Ops.push_back(EmitScalarOrConstFoldImmArg(ICEArguments, 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(Intrinsic::ctlz, Ops[0]->getType());
296     Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
297     if (Result->getType() != ResultType)
298       Result =
299           Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false, "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(Intrinsic::cttz, Ops[0]->getType());
305     Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
306     if (Result->getType() != ResultType)
307       Result =
308           Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false, "cast");
309     return Result;
310   }
311 
312   // Zihintntl
313   case RISCV::BI__builtin_riscv_ntl_load: {
314     llvm::Type *ResTy = ConvertType(E->getType());
315     unsigned DomainVal = 5; // Default __RISCV_NTLH_ALL
316     if (Ops.size() == 2)
317       DomainVal = cast<ConstantInt>(Ops[1])->getZExtValue();
318 
319     llvm::MDNode *RISCVDomainNode = llvm::MDNode::get(
320         getLLVMContext(),
321         llvm::ConstantAsMetadata::get(Builder.getInt32(DomainVal)));
322     llvm::MDNode *NontemporalNode = llvm::MDNode::get(
323         getLLVMContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
324 
325     int Width;
326     if(ResTy->isScalableTy()) {
327       const ScalableVectorType *SVTy = cast<ScalableVectorType>(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         Address(Ops[0], ResTy, CharUnits::fromQuantity(Width / 8)));
335 
336     Load->setMetadata(llvm::LLVMContext::MD_nontemporal, NontemporalNode);
337     Load->setMetadata(CGM.getModule().getMDKindID("riscv-nontemporal-domain"),
338                       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>(Ops[2])->getZExtValue();
346 
347     llvm::MDNode *RISCVDomainNode = llvm::MDNode::get(
348         getLLVMContext(),
349         llvm::ConstantAsMetadata::get(Builder.getInt32(DomainVal)));
350     llvm::MDNode *NontemporalNode = llvm::MDNode::get(
351         getLLVMContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
352 
353     StoreInst *Store = Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
354     Store->setMetadata(llvm::LLVMContext::MD_nontemporal, NontemporalNode);
355     Store->setMetadata(CGM.getModule().getMDKindID("riscv-nontemporal-domain"),
356                        RISCVDomainNode);
357 
358     return Store;
359   }
360   // Zihintpause
361   case RISCV::BI__builtin_riscv_pause: {
362     llvm::Function *Fn = CGM.getIntrinsic(llvm::Intrinsic::riscv_pause);
363     return Builder.CreateCall(Fn, {});
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(Builder.CreateTrunc(Ops[0], Int8Ty), Int32Ty,
387                               "extbs");
388   case RISCV::BI__builtin_riscv_cv_alu_extbz:
389     return Builder.CreateZExt(Builder.CreateTrunc(Ops[0], Int8Ty), Int32Ty,
390                               "extbz");
391   case RISCV::BI__builtin_riscv_cv_alu_exths:
392     return Builder.CreateSExt(Builder.CreateTrunc(Ops[0], Int16Ty), Int32Ty,
393                               "exths");
394   case RISCV::BI__builtin_riscv_cv_alu_exthz:
395     return Builder.CreateZExt(Builder.CreateTrunc(Ops[0], Int16Ty), Int32Ty,
396                               "exthz");
397   case RISCV::BI__builtin_riscv_cv_alu_sle:
398     return Builder.CreateZExt(Builder.CreateICmpSLE(Ops[0], Ops[1]), Int32Ty,
399                               "sle");
400   case RISCV::BI__builtin_riscv_cv_alu_sleu:
401     return Builder.CreateZExt(Builder.CreateICmpULE(Ops[0], Ops[1]), Int32Ty,
402                               "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(ID, IntrinsicTypes);
429   return Builder.CreateCall(F, Ops, "");
430 }
431