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