1 //===---------- PPC.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 "CGBuiltin.h" 14 #include "clang/Basic/TargetBuiltins.h" 15 #include "llvm/IR/InlineAsm.h" 16 #include "llvm/IR/IntrinsicsPowerPC.h" 17 #include "llvm/Support/ScopedPrinter.h" 18 19 using namespace clang; 20 using namespace CodeGen; 21 using namespace llvm; 22 23 static llvm::Value *emitPPCLoadReserveIntrinsic(CodeGenFunction &CGF, 24 unsigned BuiltinID, 25 const CallExpr *E) { 26 Value *Addr = CGF.EmitScalarExpr(E->getArg(0)); 27 28 SmallString<64> Asm; 29 raw_svector_ostream AsmOS(Asm); 30 llvm::IntegerType *RetType = CGF.Int32Ty; 31 32 switch (BuiltinID) { 33 case clang::PPC::BI__builtin_ppc_ldarx: 34 AsmOS << "ldarx "; 35 RetType = CGF.Int64Ty; 36 break; 37 case clang::PPC::BI__builtin_ppc_lwarx: 38 AsmOS << "lwarx "; 39 RetType = CGF.Int32Ty; 40 break; 41 case clang::PPC::BI__builtin_ppc_lharx: 42 AsmOS << "lharx "; 43 RetType = CGF.Int16Ty; 44 break; 45 case clang::PPC::BI__builtin_ppc_lbarx: 46 AsmOS << "lbarx "; 47 RetType = CGF.Int8Ty; 48 break; 49 default: 50 llvm_unreachable("Expected only PowerPC load reserve intrinsics"); 51 } 52 53 AsmOS << "$0, ${1:y}"; 54 55 std::string Constraints = "=r,*Z,~{memory}"; 56 std::string_view MachineClobbers = CGF.getTarget().getClobbers(); 57 if (!MachineClobbers.empty()) { 58 Constraints += ','; 59 Constraints += MachineClobbers; 60 } 61 62 llvm::Type *PtrType = CGF.UnqualPtrTy; 63 llvm::FunctionType *FTy = llvm::FunctionType::get(RetType, {PtrType}, false); 64 65 llvm::InlineAsm *IA = 66 llvm::InlineAsm::get(FTy, Asm, Constraints, /*hasSideEffects=*/true); 67 llvm::CallInst *CI = CGF.Builder.CreateCall(IA, {Addr}); 68 CI->addParamAttr( 69 0, Attribute::get(CGF.getLLVMContext(), Attribute::ElementType, RetType)); 70 return CI; 71 } 72 73 Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, 74 const CallExpr *E) { 75 // Do not emit the builtin arguments in the arguments of a function call, 76 // because the evaluation order of function arguments is not specified in C++. 77 // This is important when testing to ensure the arguments are emitted in the 78 // same order every time. Eg: 79 // Instead of: 80 // return Builder.CreateFDiv(EmitScalarExpr(E->getArg(0)), 81 // EmitScalarExpr(E->getArg(1)), "swdiv"); 82 // Use: 83 // Value *Op0 = EmitScalarExpr(E->getArg(0)); 84 // Value *Op1 = EmitScalarExpr(E->getArg(1)); 85 // return Builder.CreateFDiv(Op0, Op1, "swdiv") 86 87 Intrinsic::ID ID = Intrinsic::not_intrinsic; 88 89 #include "llvm/TargetParser/PPCTargetParser.def" 90 auto GenAIXPPCBuiltinCpuExpr = [&](unsigned SupportMethod, unsigned FieldIdx, 91 unsigned Mask, CmpInst::Predicate CompOp, 92 unsigned OpValue) -> Value * { 93 if (SupportMethod == BUILTIN_PPC_FALSE) 94 return llvm::ConstantInt::getFalse(ConvertType(E->getType())); 95 96 if (SupportMethod == BUILTIN_PPC_TRUE) 97 return llvm::ConstantInt::getTrue(ConvertType(E->getType())); 98 99 assert(SupportMethod <= SYS_CALL && "Invalid value for SupportMethod."); 100 101 llvm::Value *FieldValue = nullptr; 102 if (SupportMethod == USE_SYS_CONF) { 103 llvm::Type *STy = llvm::StructType::get(PPC_SYSTEMCONFIG_TYPE); 104 llvm::Constant *SysConf = 105 CGM.CreateRuntimeVariable(STy, "_system_configuration"); 106 107 // Grab the appropriate field from _system_configuration. 108 llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0), 109 ConstantInt::get(Int32Ty, FieldIdx)}; 110 111 FieldValue = Builder.CreateInBoundsGEP(STy, SysConf, Idxs); 112 FieldValue = Builder.CreateAlignedLoad(Int32Ty, FieldValue, 113 CharUnits::fromQuantity(4)); 114 } else if (SupportMethod == SYS_CALL) { 115 llvm::FunctionType *FTy = 116 llvm::FunctionType::get(Int64Ty, Int32Ty, false); 117 llvm::FunctionCallee Func = 118 CGM.CreateRuntimeFunction(FTy, "getsystemcfg"); 119 120 FieldValue = 121 Builder.CreateCall(Func, {ConstantInt::get(Int32Ty, FieldIdx)}); 122 } 123 assert(FieldValue && 124 "SupportMethod value is not defined in PPCTargetParser.def."); 125 126 if (Mask) 127 FieldValue = Builder.CreateAnd(FieldValue, Mask); 128 129 llvm::Type *ValueType = FieldValue->getType(); 130 bool IsValueType64Bit = ValueType->isIntegerTy(64); 131 assert( 132 (IsValueType64Bit || ValueType->isIntegerTy(32)) && 133 "Only 32/64-bit integers are supported in GenAIXPPCBuiltinCpuExpr()."); 134 135 return Builder.CreateICmp( 136 CompOp, FieldValue, 137 ConstantInt::get(IsValueType64Bit ? Int64Ty : Int32Ty, OpValue)); 138 }; 139 140 switch (BuiltinID) { 141 default: return nullptr; 142 143 case Builtin::BI__builtin_cpu_is: { 144 const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts(); 145 StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString(); 146 llvm::Triple Triple = getTarget().getTriple(); 147 148 typedef std::tuple<unsigned, unsigned, unsigned, unsigned> CPUInfo; 149 150 auto [LinuxSupportMethod, LinuxIDValue, AIXSupportMethod, AIXIDValue] = 151 static_cast<CPUInfo>(StringSwitch<CPUInfo>(CPUStr) 152 #define PPC_CPU(NAME, Linux_SUPPORT_METHOD, LinuxID, AIX_SUPPORT_METHOD, \ 153 AIXID) \ 154 .Case(NAME, {Linux_SUPPORT_METHOD, LinuxID, AIX_SUPPORT_METHOD, AIXID}) 155 #include "llvm/TargetParser/PPCTargetParser.def" 156 .Default({BUILTIN_PPC_UNSUPPORTED, 0, 157 BUILTIN_PPC_UNSUPPORTED, 0})); 158 159 if (Triple.isOSAIX()) { 160 assert((AIXSupportMethod != BUILTIN_PPC_UNSUPPORTED) && 161 "Invalid CPU name. Missed by SemaChecking?"); 162 return GenAIXPPCBuiltinCpuExpr(AIXSupportMethod, AIX_SYSCON_IMPL_IDX, 0, 163 ICmpInst::ICMP_EQ, AIXIDValue); 164 } 165 166 assert(Triple.isOSLinux() && 167 "__builtin_cpu_is() is only supported for AIX and Linux."); 168 169 assert((LinuxSupportMethod != BUILTIN_PPC_UNSUPPORTED) && 170 "Invalid CPU name. Missed by SemaChecking?"); 171 172 if (LinuxSupportMethod == BUILTIN_PPC_FALSE) 173 return llvm::ConstantInt::getFalse(ConvertType(E->getType())); 174 175 Value *Op0 = llvm::ConstantInt::get(Int32Ty, PPC_FAWORD_CPUID); 176 llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_fixed_addr_ld); 177 Value *TheCall = Builder.CreateCall(F, {Op0}, "cpu_is"); 178 return Builder.CreateICmpEQ(TheCall, 179 llvm::ConstantInt::get(Int32Ty, LinuxIDValue)); 180 } 181 case Builtin::BI__builtin_cpu_supports: { 182 llvm::Triple Triple = getTarget().getTriple(); 183 const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts(); 184 StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString(); 185 if (Triple.isOSAIX()) { 186 typedef std::tuple<unsigned, unsigned, unsigned, CmpInst::Predicate, 187 unsigned> 188 CPUSupportType; 189 auto [SupportMethod, FieldIdx, Mask, CompOp, Value] = 190 static_cast<CPUSupportType>(StringSwitch<CPUSupportType>(CPUStr) 191 #define PPC_AIX_FEATURE(NAME, DESC, SUPPORT_METHOD, INDEX, MASK, COMP_OP, \ 192 VALUE) \ 193 .Case(NAME, {SUPPORT_METHOD, INDEX, MASK, COMP_OP, VALUE}) 194 #include "llvm/TargetParser/PPCTargetParser.def" 195 .Default({BUILTIN_PPC_FALSE, 0, 0, 196 CmpInst::Predicate(), 0})); 197 return GenAIXPPCBuiltinCpuExpr(SupportMethod, FieldIdx, Mask, CompOp, 198 Value); 199 } 200 201 assert(Triple.isOSLinux() && 202 "__builtin_cpu_supports() is only supported for AIX and Linux."); 203 auto [FeatureWord, BitMask] = 204 StringSwitch<std::pair<unsigned, unsigned>>(CPUStr) 205 #define PPC_LNX_FEATURE(Name, Description, EnumName, Bitmask, FA_WORD) \ 206 .Case(Name, {FA_WORD, Bitmask}) 207 #include "llvm/TargetParser/PPCTargetParser.def" 208 .Default({0, 0}); 209 if (!BitMask) 210 return Builder.getFalse(); 211 Value *Op0 = llvm::ConstantInt::get(Int32Ty, FeatureWord); 212 llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_fixed_addr_ld); 213 Value *TheCall = Builder.CreateCall(F, {Op0}, "cpu_supports"); 214 Value *Mask = 215 Builder.CreateAnd(TheCall, llvm::ConstantInt::get(Int32Ty, BitMask)); 216 return Builder.CreateICmpNE(Mask, llvm::Constant::getNullValue(Int32Ty)); 217 #undef PPC_FAWORD_HWCAP 218 #undef PPC_FAWORD_HWCAP2 219 #undef PPC_FAWORD_CPUID 220 } 221 222 // __builtin_ppc_get_timebase is GCC 4.8+'s PowerPC-specific name for what we 223 // call __builtin_readcyclecounter. 224 case PPC::BI__builtin_ppc_get_timebase: 225 return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::readcyclecounter)); 226 227 // vec_ld, vec_xl_be, vec_lvsl, vec_lvsr 228 case PPC::BI__builtin_altivec_lvx: 229 case PPC::BI__builtin_altivec_lvxl: 230 case PPC::BI__builtin_altivec_lvebx: 231 case PPC::BI__builtin_altivec_lvehx: 232 case PPC::BI__builtin_altivec_lvewx: 233 case PPC::BI__builtin_altivec_lvsl: 234 case PPC::BI__builtin_altivec_lvsr: 235 case PPC::BI__builtin_vsx_lxvd2x: 236 case PPC::BI__builtin_vsx_lxvw4x: 237 case PPC::BI__builtin_vsx_lxvd2x_be: 238 case PPC::BI__builtin_vsx_lxvw4x_be: 239 case PPC::BI__builtin_vsx_lxvl: 240 case PPC::BI__builtin_vsx_lxvll: 241 { 242 SmallVector<Value *, 2> Ops; 243 Ops.push_back(EmitScalarExpr(E->getArg(0))); 244 Ops.push_back(EmitScalarExpr(E->getArg(1))); 245 if (!(BuiltinID == PPC::BI__builtin_vsx_lxvl || 246 BuiltinID == PPC::BI__builtin_vsx_lxvll)) { 247 Ops[0] = Builder.CreateGEP(Int8Ty, Ops[1], Ops[0]); 248 Ops.pop_back(); 249 } 250 251 switch (BuiltinID) { 252 default: llvm_unreachable("Unsupported ld/lvsl/lvsr intrinsic!"); 253 case PPC::BI__builtin_altivec_lvx: 254 ID = Intrinsic::ppc_altivec_lvx; 255 break; 256 case PPC::BI__builtin_altivec_lvxl: 257 ID = Intrinsic::ppc_altivec_lvxl; 258 break; 259 case PPC::BI__builtin_altivec_lvebx: 260 ID = Intrinsic::ppc_altivec_lvebx; 261 break; 262 case PPC::BI__builtin_altivec_lvehx: 263 ID = Intrinsic::ppc_altivec_lvehx; 264 break; 265 case PPC::BI__builtin_altivec_lvewx: 266 ID = Intrinsic::ppc_altivec_lvewx; 267 break; 268 case PPC::BI__builtin_altivec_lvsl: 269 ID = Intrinsic::ppc_altivec_lvsl; 270 break; 271 case PPC::BI__builtin_altivec_lvsr: 272 ID = Intrinsic::ppc_altivec_lvsr; 273 break; 274 case PPC::BI__builtin_vsx_lxvd2x: 275 ID = Intrinsic::ppc_vsx_lxvd2x; 276 break; 277 case PPC::BI__builtin_vsx_lxvw4x: 278 ID = Intrinsic::ppc_vsx_lxvw4x; 279 break; 280 case PPC::BI__builtin_vsx_lxvd2x_be: 281 ID = Intrinsic::ppc_vsx_lxvd2x_be; 282 break; 283 case PPC::BI__builtin_vsx_lxvw4x_be: 284 ID = Intrinsic::ppc_vsx_lxvw4x_be; 285 break; 286 case PPC::BI__builtin_vsx_lxvl: 287 ID = Intrinsic::ppc_vsx_lxvl; 288 break; 289 case PPC::BI__builtin_vsx_lxvll: 290 ID = Intrinsic::ppc_vsx_lxvll; 291 break; 292 } 293 llvm::Function *F = CGM.getIntrinsic(ID); 294 return Builder.CreateCall(F, Ops, ""); 295 } 296 297 // vec_st, vec_xst_be 298 case PPC::BI__builtin_altivec_stvx: 299 case PPC::BI__builtin_altivec_stvxl: 300 case PPC::BI__builtin_altivec_stvebx: 301 case PPC::BI__builtin_altivec_stvehx: 302 case PPC::BI__builtin_altivec_stvewx: 303 case PPC::BI__builtin_vsx_stxvd2x: 304 case PPC::BI__builtin_vsx_stxvw4x: 305 case PPC::BI__builtin_vsx_stxvd2x_be: 306 case PPC::BI__builtin_vsx_stxvw4x_be: 307 case PPC::BI__builtin_vsx_stxvl: 308 case PPC::BI__builtin_vsx_stxvll: 309 { 310 SmallVector<Value *, 3> Ops; 311 Ops.push_back(EmitScalarExpr(E->getArg(0))); 312 Ops.push_back(EmitScalarExpr(E->getArg(1))); 313 Ops.push_back(EmitScalarExpr(E->getArg(2))); 314 if (!(BuiltinID == PPC::BI__builtin_vsx_stxvl || 315 BuiltinID == PPC::BI__builtin_vsx_stxvll)) { 316 Ops[1] = Builder.CreateGEP(Int8Ty, Ops[2], Ops[1]); 317 Ops.pop_back(); 318 } 319 320 switch (BuiltinID) { 321 default: llvm_unreachable("Unsupported st intrinsic!"); 322 case PPC::BI__builtin_altivec_stvx: 323 ID = Intrinsic::ppc_altivec_stvx; 324 break; 325 case PPC::BI__builtin_altivec_stvxl: 326 ID = Intrinsic::ppc_altivec_stvxl; 327 break; 328 case PPC::BI__builtin_altivec_stvebx: 329 ID = Intrinsic::ppc_altivec_stvebx; 330 break; 331 case PPC::BI__builtin_altivec_stvehx: 332 ID = Intrinsic::ppc_altivec_stvehx; 333 break; 334 case PPC::BI__builtin_altivec_stvewx: 335 ID = Intrinsic::ppc_altivec_stvewx; 336 break; 337 case PPC::BI__builtin_vsx_stxvd2x: 338 ID = Intrinsic::ppc_vsx_stxvd2x; 339 break; 340 case PPC::BI__builtin_vsx_stxvw4x: 341 ID = Intrinsic::ppc_vsx_stxvw4x; 342 break; 343 case PPC::BI__builtin_vsx_stxvd2x_be: 344 ID = Intrinsic::ppc_vsx_stxvd2x_be; 345 break; 346 case PPC::BI__builtin_vsx_stxvw4x_be: 347 ID = Intrinsic::ppc_vsx_stxvw4x_be; 348 break; 349 case PPC::BI__builtin_vsx_stxvl: 350 ID = Intrinsic::ppc_vsx_stxvl; 351 break; 352 case PPC::BI__builtin_vsx_stxvll: 353 ID = Intrinsic::ppc_vsx_stxvll; 354 break; 355 } 356 llvm::Function *F = CGM.getIntrinsic(ID); 357 return Builder.CreateCall(F, Ops, ""); 358 } 359 case PPC::BI__builtin_vsx_ldrmb: { 360 // Essentially boils down to performing an unaligned VMX load sequence so 361 // as to avoid crossing a page boundary and then shuffling the elements 362 // into the right side of the vector register. 363 Value *Op0 = EmitScalarExpr(E->getArg(0)); 364 Value *Op1 = EmitScalarExpr(E->getArg(1)); 365 int64_t NumBytes = cast<ConstantInt>(Op1)->getZExtValue(); 366 llvm::Type *ResTy = ConvertType(E->getType()); 367 bool IsLE = getTarget().isLittleEndian(); 368 369 // If the user wants the entire vector, just load the entire vector. 370 if (NumBytes == 16) { 371 Value *LD = 372 Builder.CreateLoad(Address(Op0, ResTy, CharUnits::fromQuantity(1))); 373 if (!IsLE) 374 return LD; 375 376 // Reverse the bytes on LE. 377 SmallVector<int, 16> RevMask; 378 for (int Idx = 0; Idx < 16; Idx++) 379 RevMask.push_back(15 - Idx); 380 return Builder.CreateShuffleVector(LD, LD, RevMask); 381 } 382 383 llvm::Function *Lvx = CGM.getIntrinsic(Intrinsic::ppc_altivec_lvx); 384 llvm::Function *Lvs = CGM.getIntrinsic(IsLE ? Intrinsic::ppc_altivec_lvsr 385 : Intrinsic::ppc_altivec_lvsl); 386 llvm::Function *Vperm = CGM.getIntrinsic(Intrinsic::ppc_altivec_vperm); 387 Value *HiMem = Builder.CreateGEP( 388 Int8Ty, Op0, ConstantInt::get(Op1->getType(), NumBytes - 1)); 389 Value *LoLd = Builder.CreateCall(Lvx, Op0, "ld.lo"); 390 Value *HiLd = Builder.CreateCall(Lvx, HiMem, "ld.hi"); 391 Value *Mask1 = Builder.CreateCall(Lvs, Op0, "mask1"); 392 393 Op0 = IsLE ? HiLd : LoLd; 394 Op1 = IsLE ? LoLd : HiLd; 395 Value *AllElts = Builder.CreateCall(Vperm, {Op0, Op1, Mask1}, "shuffle1"); 396 Constant *Zero = llvm::Constant::getNullValue(IsLE ? ResTy : AllElts->getType()); 397 398 if (IsLE) { 399 SmallVector<int, 16> Consts; 400 for (int Idx = 0; Idx < 16; Idx++) { 401 int Val = (NumBytes - Idx - 1 >= 0) ? (NumBytes - Idx - 1) 402 : 16 - (NumBytes - Idx); 403 Consts.push_back(Val); 404 } 405 return Builder.CreateShuffleVector(Builder.CreateBitCast(AllElts, ResTy), 406 Zero, Consts); 407 } 408 SmallVector<Constant *, 16> Consts; 409 for (int Idx = 0; Idx < 16; Idx++) 410 Consts.push_back(Builder.getInt8(NumBytes + Idx)); 411 Value *Mask2 = ConstantVector::get(Consts); 412 return Builder.CreateBitCast( 413 Builder.CreateCall(Vperm, {Zero, AllElts, Mask2}, "shuffle2"), ResTy); 414 } 415 case PPC::BI__builtin_vsx_strmb: { 416 Value *Op0 = EmitScalarExpr(E->getArg(0)); 417 Value *Op1 = EmitScalarExpr(E->getArg(1)); 418 Value *Op2 = EmitScalarExpr(E->getArg(2)); 419 int64_t NumBytes = cast<ConstantInt>(Op1)->getZExtValue(); 420 bool IsLE = getTarget().isLittleEndian(); 421 auto StoreSubVec = [&](unsigned Width, unsigned Offset, unsigned EltNo) { 422 // Storing the whole vector, simply store it on BE and reverse bytes and 423 // store on LE. 424 if (Width == 16) { 425 Value *StVec = Op2; 426 if (IsLE) { 427 SmallVector<int, 16> RevMask; 428 for (int Idx = 0; Idx < 16; Idx++) 429 RevMask.push_back(15 - Idx); 430 StVec = Builder.CreateShuffleVector(Op2, Op2, RevMask); 431 } 432 return Builder.CreateStore( 433 StVec, Address(Op0, Op2->getType(), CharUnits::fromQuantity(1))); 434 } 435 auto *ConvTy = Int64Ty; 436 unsigned NumElts = 0; 437 switch (Width) { 438 default: 439 llvm_unreachable("width for stores must be a power of 2"); 440 case 8: 441 ConvTy = Int64Ty; 442 NumElts = 2; 443 break; 444 case 4: 445 ConvTy = Int32Ty; 446 NumElts = 4; 447 break; 448 case 2: 449 ConvTy = Int16Ty; 450 NumElts = 8; 451 break; 452 case 1: 453 ConvTy = Int8Ty; 454 NumElts = 16; 455 break; 456 } 457 Value *Vec = Builder.CreateBitCast( 458 Op2, llvm::FixedVectorType::get(ConvTy, NumElts)); 459 Value *Ptr = 460 Builder.CreateGEP(Int8Ty, Op0, ConstantInt::get(Int64Ty, Offset)); 461 Value *Elt = Builder.CreateExtractElement(Vec, EltNo); 462 if (IsLE && Width > 1) { 463 Function *F = CGM.getIntrinsic(Intrinsic::bswap, ConvTy); 464 Elt = Builder.CreateCall(F, Elt); 465 } 466 return Builder.CreateStore( 467 Elt, Address(Ptr, ConvTy, CharUnits::fromQuantity(1))); 468 }; 469 unsigned Stored = 0; 470 unsigned RemainingBytes = NumBytes; 471 Value *Result; 472 if (NumBytes == 16) 473 return StoreSubVec(16, 0, 0); 474 if (NumBytes >= 8) { 475 Result = StoreSubVec(8, NumBytes - 8, IsLE ? 0 : 1); 476 RemainingBytes -= 8; 477 Stored += 8; 478 } 479 if (RemainingBytes >= 4) { 480 Result = StoreSubVec(4, NumBytes - Stored - 4, 481 IsLE ? (Stored >> 2) : 3 - (Stored >> 2)); 482 RemainingBytes -= 4; 483 Stored += 4; 484 } 485 if (RemainingBytes >= 2) { 486 Result = StoreSubVec(2, NumBytes - Stored - 2, 487 IsLE ? (Stored >> 1) : 7 - (Stored >> 1)); 488 RemainingBytes -= 2; 489 Stored += 2; 490 } 491 if (RemainingBytes) 492 Result = 493 StoreSubVec(1, NumBytes - Stored - 1, IsLE ? Stored : 15 - Stored); 494 return Result; 495 } 496 // Square root 497 case PPC::BI__builtin_vsx_xvsqrtsp: 498 case PPC::BI__builtin_vsx_xvsqrtdp: { 499 llvm::Type *ResultType = ConvertType(E->getType()); 500 Value *X = EmitScalarExpr(E->getArg(0)); 501 if (Builder.getIsFPConstrained()) { 502 llvm::Function *F = CGM.getIntrinsic( 503 Intrinsic::experimental_constrained_sqrt, ResultType); 504 return Builder.CreateConstrainedFPCall(F, X); 505 } else { 506 llvm::Function *F = CGM.getIntrinsic(Intrinsic::sqrt, ResultType); 507 return Builder.CreateCall(F, X); 508 } 509 } 510 // Count leading zeros 511 case PPC::BI__builtin_altivec_vclzb: 512 case PPC::BI__builtin_altivec_vclzh: 513 case PPC::BI__builtin_altivec_vclzw: 514 case PPC::BI__builtin_altivec_vclzd: { 515 llvm::Type *ResultType = ConvertType(E->getType()); 516 Value *X = EmitScalarExpr(E->getArg(0)); 517 Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false); 518 Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ResultType); 519 return Builder.CreateCall(F, {X, Undef}); 520 } 521 case PPC::BI__builtin_altivec_vctzb: 522 case PPC::BI__builtin_altivec_vctzh: 523 case PPC::BI__builtin_altivec_vctzw: 524 case PPC::BI__builtin_altivec_vctzd: { 525 llvm::Type *ResultType = ConvertType(E->getType()); 526 Value *X = EmitScalarExpr(E->getArg(0)); 527 Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false); 528 Function *F = CGM.getIntrinsic(Intrinsic::cttz, ResultType); 529 return Builder.CreateCall(F, {X, Undef}); 530 } 531 case PPC::BI__builtin_altivec_vinsd: 532 case PPC::BI__builtin_altivec_vinsw: 533 case PPC::BI__builtin_altivec_vinsd_elt: 534 case PPC::BI__builtin_altivec_vinsw_elt: { 535 llvm::Type *ResultType = ConvertType(E->getType()); 536 Value *Op0 = EmitScalarExpr(E->getArg(0)); 537 Value *Op1 = EmitScalarExpr(E->getArg(1)); 538 Value *Op2 = EmitScalarExpr(E->getArg(2)); 539 540 bool IsUnaligned = (BuiltinID == PPC::BI__builtin_altivec_vinsw || 541 BuiltinID == PPC::BI__builtin_altivec_vinsd); 542 543 bool Is32bit = (BuiltinID == PPC::BI__builtin_altivec_vinsw || 544 BuiltinID == PPC::BI__builtin_altivec_vinsw_elt); 545 546 // The third argument must be a compile time constant. 547 ConstantInt *ArgCI = dyn_cast<ConstantInt>(Op2); 548 assert(ArgCI && 549 "Third Arg to vinsw/vinsd intrinsic must be a constant integer!"); 550 551 // Valid value for the third argument is dependent on the input type and 552 // builtin called. 553 int ValidMaxValue = 0; 554 if (IsUnaligned) 555 ValidMaxValue = (Is32bit) ? 12 : 8; 556 else 557 ValidMaxValue = (Is32bit) ? 3 : 1; 558 559 // Get value of third argument. 560 int64_t ConstArg = ArgCI->getSExtValue(); 561 562 // Compose range checking error message. 563 std::string RangeErrMsg = IsUnaligned ? "byte" : "element"; 564 RangeErrMsg += " number " + llvm::to_string(ConstArg); 565 RangeErrMsg += " is outside of the valid range [0, "; 566 RangeErrMsg += llvm::to_string(ValidMaxValue) + "]"; 567 568 // Issue error if third argument is not within the valid range. 569 if (ConstArg < 0 || ConstArg > ValidMaxValue) 570 CGM.Error(E->getExprLoc(), RangeErrMsg); 571 572 // Input to vec_replace_elt is an element index, convert to byte index. 573 if (!IsUnaligned) { 574 ConstArg *= Is32bit ? 4 : 8; 575 // Fix the constant according to endianess. 576 if (getTarget().isLittleEndian()) 577 ConstArg = (Is32bit ? 12 : 8) - ConstArg; 578 } 579 580 ID = Is32bit ? Intrinsic::ppc_altivec_vinsw : Intrinsic::ppc_altivec_vinsd; 581 Op2 = ConstantInt::getSigned(Int32Ty, ConstArg); 582 // Casting input to vector int as per intrinsic definition. 583 Op0 = 584 Is32bit 585 ? Builder.CreateBitCast(Op0, llvm::FixedVectorType::get(Int32Ty, 4)) 586 : Builder.CreateBitCast(Op0, 587 llvm::FixedVectorType::get(Int64Ty, 2)); 588 return Builder.CreateBitCast( 589 Builder.CreateCall(CGM.getIntrinsic(ID), {Op0, Op1, Op2}), ResultType); 590 } 591 case PPC::BI__builtin_altivec_vadduqm: 592 case PPC::BI__builtin_altivec_vsubuqm: { 593 Value *Op0 = EmitScalarExpr(E->getArg(0)); 594 Value *Op1 = EmitScalarExpr(E->getArg(1)); 595 llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128); 596 Op0 = Builder.CreateBitCast(Op0, llvm::FixedVectorType::get(Int128Ty, 1)); 597 Op1 = Builder.CreateBitCast(Op1, llvm::FixedVectorType::get(Int128Ty, 1)); 598 if (BuiltinID == PPC::BI__builtin_altivec_vadduqm) 599 return Builder.CreateAdd(Op0, Op1, "vadduqm"); 600 else 601 return Builder.CreateSub(Op0, Op1, "vsubuqm"); 602 } 603 case PPC::BI__builtin_altivec_vaddcuq_c: 604 case PPC::BI__builtin_altivec_vsubcuq_c: { 605 SmallVector<Value *, 2> Ops; 606 Value *Op0 = EmitScalarExpr(E->getArg(0)); 607 Value *Op1 = EmitScalarExpr(E->getArg(1)); 608 llvm::Type *V1I128Ty = llvm::FixedVectorType::get( 609 llvm::IntegerType::get(getLLVMContext(), 128), 1); 610 Ops.push_back(Builder.CreateBitCast(Op0, V1I128Ty)); 611 Ops.push_back(Builder.CreateBitCast(Op1, V1I128Ty)); 612 ID = (BuiltinID == PPC::BI__builtin_altivec_vaddcuq_c) 613 ? Intrinsic::ppc_altivec_vaddcuq 614 : Intrinsic::ppc_altivec_vsubcuq; 615 return Builder.CreateCall(CGM.getIntrinsic(ID), Ops, ""); 616 } 617 case PPC::BI__builtin_altivec_vaddeuqm_c: 618 case PPC::BI__builtin_altivec_vaddecuq_c: 619 case PPC::BI__builtin_altivec_vsubeuqm_c: 620 case PPC::BI__builtin_altivec_vsubecuq_c: { 621 SmallVector<Value *, 3> Ops; 622 Value *Op0 = EmitScalarExpr(E->getArg(0)); 623 Value *Op1 = EmitScalarExpr(E->getArg(1)); 624 Value *Op2 = EmitScalarExpr(E->getArg(2)); 625 llvm::Type *V1I128Ty = llvm::FixedVectorType::get( 626 llvm::IntegerType::get(getLLVMContext(), 128), 1); 627 Ops.push_back(Builder.CreateBitCast(Op0, V1I128Ty)); 628 Ops.push_back(Builder.CreateBitCast(Op1, V1I128Ty)); 629 Ops.push_back(Builder.CreateBitCast(Op2, V1I128Ty)); 630 switch (BuiltinID) { 631 default: 632 llvm_unreachable("Unsupported intrinsic!"); 633 case PPC::BI__builtin_altivec_vaddeuqm_c: 634 ID = Intrinsic::ppc_altivec_vaddeuqm; 635 break; 636 case PPC::BI__builtin_altivec_vaddecuq_c: 637 ID = Intrinsic::ppc_altivec_vaddecuq; 638 break; 639 case PPC::BI__builtin_altivec_vsubeuqm_c: 640 ID = Intrinsic::ppc_altivec_vsubeuqm; 641 break; 642 case PPC::BI__builtin_altivec_vsubecuq_c: 643 ID = Intrinsic::ppc_altivec_vsubecuq; 644 break; 645 } 646 return Builder.CreateCall(CGM.getIntrinsic(ID), Ops, ""); 647 } 648 case PPC::BI__builtin_ppc_rldimi: 649 case PPC::BI__builtin_ppc_rlwimi: { 650 Value *Op0 = EmitScalarExpr(E->getArg(0)); 651 Value *Op1 = EmitScalarExpr(E->getArg(1)); 652 Value *Op2 = EmitScalarExpr(E->getArg(2)); 653 Value *Op3 = EmitScalarExpr(E->getArg(3)); 654 // rldimi is 64-bit instruction, expand the intrinsic before isel to 655 // leverage peephole and avoid legalization efforts. 656 if (BuiltinID == PPC::BI__builtin_ppc_rldimi && 657 !getTarget().getTriple().isPPC64()) { 658 Function *F = CGM.getIntrinsic(Intrinsic::fshl, Op0->getType()); 659 Op2 = Builder.CreateZExt(Op2, Int64Ty); 660 Value *Shift = Builder.CreateCall(F, {Op0, Op0, Op2}); 661 return Builder.CreateOr(Builder.CreateAnd(Shift, Op3), 662 Builder.CreateAnd(Op1, Builder.CreateNot(Op3))); 663 } 664 return Builder.CreateCall( 665 CGM.getIntrinsic(BuiltinID == PPC::BI__builtin_ppc_rldimi 666 ? Intrinsic::ppc_rldimi 667 : Intrinsic::ppc_rlwimi), 668 {Op0, Op1, Op2, Op3}); 669 } 670 case PPC::BI__builtin_ppc_rlwnm: { 671 Value *Op0 = EmitScalarExpr(E->getArg(0)); 672 Value *Op1 = EmitScalarExpr(E->getArg(1)); 673 Value *Op2 = EmitScalarExpr(E->getArg(2)); 674 return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_rlwnm), 675 {Op0, Op1, Op2}); 676 } 677 case PPC::BI__builtin_ppc_poppar4: 678 case PPC::BI__builtin_ppc_poppar8: { 679 Value *Op0 = EmitScalarExpr(E->getArg(0)); 680 llvm::Type *ArgType = Op0->getType(); 681 Function *F = CGM.getIntrinsic(Intrinsic::ctpop, ArgType); 682 Value *Tmp = Builder.CreateCall(F, Op0); 683 684 llvm::Type *ResultType = ConvertType(E->getType()); 685 Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1)); 686 if (Result->getType() != ResultType) 687 Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, 688 "cast"); 689 return Result; 690 } 691 case PPC::BI__builtin_ppc_cmpb: { 692 Value *Op0 = EmitScalarExpr(E->getArg(0)); 693 Value *Op1 = EmitScalarExpr(E->getArg(1)); 694 if (getTarget().getTriple().isPPC64()) { 695 Function *F = 696 CGM.getIntrinsic(Intrinsic::ppc_cmpb, {Int64Ty, Int64Ty, Int64Ty}); 697 return Builder.CreateCall(F, {Op0, Op1}, "cmpb"); 698 } 699 // For 32 bit, emit the code as below: 700 // %conv = trunc i64 %a to i32 701 // %conv1 = trunc i64 %b to i32 702 // %shr = lshr i64 %a, 32 703 // %conv2 = trunc i64 %shr to i32 704 // %shr3 = lshr i64 %b, 32 705 // %conv4 = trunc i64 %shr3 to i32 706 // %0 = tail call i32 @llvm.ppc.cmpb32(i32 %conv, i32 %conv1) 707 // %conv5 = zext i32 %0 to i64 708 // %1 = tail call i32 @llvm.ppc.cmpb32(i32 %conv2, i32 %conv4) 709 // %conv614 = zext i32 %1 to i64 710 // %shl = shl nuw i64 %conv614, 32 711 // %or = or i64 %shl, %conv5 712 // ret i64 %or 713 Function *F = 714 CGM.getIntrinsic(Intrinsic::ppc_cmpb, {Int32Ty, Int32Ty, Int32Ty}); 715 Value *ArgOneLo = Builder.CreateTrunc(Op0, Int32Ty); 716 Value *ArgTwoLo = Builder.CreateTrunc(Op1, Int32Ty); 717 Constant *ShiftAmt = ConstantInt::get(Int64Ty, 32); 718 Value *ArgOneHi = 719 Builder.CreateTrunc(Builder.CreateLShr(Op0, ShiftAmt), Int32Ty); 720 Value *ArgTwoHi = 721 Builder.CreateTrunc(Builder.CreateLShr(Op1, ShiftAmt), Int32Ty); 722 Value *ResLo = Builder.CreateZExt( 723 Builder.CreateCall(F, {ArgOneLo, ArgTwoLo}, "cmpb"), Int64Ty); 724 Value *ResHiShift = Builder.CreateZExt( 725 Builder.CreateCall(F, {ArgOneHi, ArgTwoHi}, "cmpb"), Int64Ty); 726 Value *ResHi = Builder.CreateShl(ResHiShift, ShiftAmt); 727 return Builder.CreateOr(ResLo, ResHi); 728 } 729 // Copy sign 730 case PPC::BI__builtin_vsx_xvcpsgnsp: 731 case PPC::BI__builtin_vsx_xvcpsgndp: { 732 llvm::Type *ResultType = ConvertType(E->getType()); 733 Value *X = EmitScalarExpr(E->getArg(0)); 734 Value *Y = EmitScalarExpr(E->getArg(1)); 735 ID = Intrinsic::copysign; 736 llvm::Function *F = CGM.getIntrinsic(ID, ResultType); 737 return Builder.CreateCall(F, {X, Y}); 738 } 739 // Rounding/truncation 740 case PPC::BI__builtin_vsx_xvrspip: 741 case PPC::BI__builtin_vsx_xvrdpip: 742 case PPC::BI__builtin_vsx_xvrdpim: 743 case PPC::BI__builtin_vsx_xvrspim: 744 case PPC::BI__builtin_vsx_xvrdpi: 745 case PPC::BI__builtin_vsx_xvrspi: 746 case PPC::BI__builtin_vsx_xvrdpic: 747 case PPC::BI__builtin_vsx_xvrspic: 748 case PPC::BI__builtin_vsx_xvrdpiz: 749 case PPC::BI__builtin_vsx_xvrspiz: { 750 llvm::Type *ResultType = ConvertType(E->getType()); 751 Value *X = EmitScalarExpr(E->getArg(0)); 752 if (BuiltinID == PPC::BI__builtin_vsx_xvrdpim || 753 BuiltinID == PPC::BI__builtin_vsx_xvrspim) 754 ID = Builder.getIsFPConstrained() 755 ? Intrinsic::experimental_constrained_floor 756 : Intrinsic::floor; 757 else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpi || 758 BuiltinID == PPC::BI__builtin_vsx_xvrspi) 759 ID = Builder.getIsFPConstrained() 760 ? Intrinsic::experimental_constrained_round 761 : Intrinsic::round; 762 else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpic || 763 BuiltinID == PPC::BI__builtin_vsx_xvrspic) 764 ID = Builder.getIsFPConstrained() 765 ? Intrinsic::experimental_constrained_rint 766 : Intrinsic::rint; 767 else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpip || 768 BuiltinID == PPC::BI__builtin_vsx_xvrspip) 769 ID = Builder.getIsFPConstrained() 770 ? Intrinsic::experimental_constrained_ceil 771 : Intrinsic::ceil; 772 else if (BuiltinID == PPC::BI__builtin_vsx_xvrdpiz || 773 BuiltinID == PPC::BI__builtin_vsx_xvrspiz) 774 ID = Builder.getIsFPConstrained() 775 ? Intrinsic::experimental_constrained_trunc 776 : Intrinsic::trunc; 777 llvm::Function *F = CGM.getIntrinsic(ID, ResultType); 778 return Builder.getIsFPConstrained() ? Builder.CreateConstrainedFPCall(F, X) 779 : Builder.CreateCall(F, X); 780 } 781 782 // Absolute value 783 case PPC::BI__builtin_vsx_xvabsdp: 784 case PPC::BI__builtin_vsx_xvabssp: { 785 llvm::Type *ResultType = ConvertType(E->getType()); 786 Value *X = EmitScalarExpr(E->getArg(0)); 787 llvm::Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType); 788 return Builder.CreateCall(F, X); 789 } 790 791 // Fastmath by default 792 case PPC::BI__builtin_ppc_recipdivf: 793 case PPC::BI__builtin_ppc_recipdivd: 794 case PPC::BI__builtin_ppc_rsqrtf: 795 case PPC::BI__builtin_ppc_rsqrtd: { 796 FastMathFlags FMF = Builder.getFastMathFlags(); 797 Builder.getFastMathFlags().setFast(); 798 llvm::Type *ResultType = ConvertType(E->getType()); 799 Value *X = EmitScalarExpr(E->getArg(0)); 800 801 if (BuiltinID == PPC::BI__builtin_ppc_recipdivf || 802 BuiltinID == PPC::BI__builtin_ppc_recipdivd) { 803 Value *Y = EmitScalarExpr(E->getArg(1)); 804 Value *FDiv = Builder.CreateFDiv(X, Y, "recipdiv"); 805 Builder.getFastMathFlags() &= (FMF); 806 return FDiv; 807 } 808 auto *One = ConstantFP::get(ResultType, 1.0); 809 llvm::Function *F = CGM.getIntrinsic(Intrinsic::sqrt, ResultType); 810 Value *FDiv = Builder.CreateFDiv(One, Builder.CreateCall(F, X), "rsqrt"); 811 Builder.getFastMathFlags() &= (FMF); 812 return FDiv; 813 } 814 case PPC::BI__builtin_ppc_alignx: { 815 Value *Op0 = EmitScalarExpr(E->getArg(0)); 816 Value *Op1 = EmitScalarExpr(E->getArg(1)); 817 ConstantInt *AlignmentCI = cast<ConstantInt>(Op0); 818 if (AlignmentCI->getValue().ugt(llvm::Value::MaximumAlignment)) 819 AlignmentCI = ConstantInt::get(AlignmentCI->getIntegerType(), 820 llvm::Value::MaximumAlignment); 821 822 emitAlignmentAssumption(Op1, E->getArg(1), 823 /*The expr loc is sufficient.*/ SourceLocation(), 824 AlignmentCI, nullptr); 825 return Op1; 826 } 827 case PPC::BI__builtin_ppc_rdlam: { 828 Value *Op0 = EmitScalarExpr(E->getArg(0)); 829 Value *Op1 = EmitScalarExpr(E->getArg(1)); 830 Value *Op2 = EmitScalarExpr(E->getArg(2)); 831 llvm::Type *Ty = Op0->getType(); 832 Value *ShiftAmt = Builder.CreateIntCast(Op1, Ty, false); 833 Function *F = CGM.getIntrinsic(Intrinsic::fshl, Ty); 834 Value *Rotate = Builder.CreateCall(F, {Op0, Op0, ShiftAmt}); 835 return Builder.CreateAnd(Rotate, Op2); 836 } 837 case PPC::BI__builtin_ppc_load2r: { 838 Function *F = CGM.getIntrinsic(Intrinsic::ppc_load2r); 839 Value *Op0 = EmitScalarExpr(E->getArg(0)); 840 Value *LoadIntrinsic = Builder.CreateCall(F, {Op0}); 841 return Builder.CreateTrunc(LoadIntrinsic, Int16Ty); 842 } 843 // FMA variations 844 case PPC::BI__builtin_ppc_fnmsub: 845 case PPC::BI__builtin_ppc_fnmsubs: 846 case PPC::BI__builtin_vsx_xvmaddadp: 847 case PPC::BI__builtin_vsx_xvmaddasp: 848 case PPC::BI__builtin_vsx_xvnmaddadp: 849 case PPC::BI__builtin_vsx_xvnmaddasp: 850 case PPC::BI__builtin_vsx_xvmsubadp: 851 case PPC::BI__builtin_vsx_xvmsubasp: 852 case PPC::BI__builtin_vsx_xvnmsubadp: 853 case PPC::BI__builtin_vsx_xvnmsubasp: { 854 llvm::Type *ResultType = ConvertType(E->getType()); 855 Value *X = EmitScalarExpr(E->getArg(0)); 856 Value *Y = EmitScalarExpr(E->getArg(1)); 857 Value *Z = EmitScalarExpr(E->getArg(2)); 858 llvm::Function *F; 859 if (Builder.getIsFPConstrained()) 860 F = CGM.getIntrinsic(Intrinsic::experimental_constrained_fma, ResultType); 861 else 862 F = CGM.getIntrinsic(Intrinsic::fma, ResultType); 863 switch (BuiltinID) { 864 case PPC::BI__builtin_vsx_xvmaddadp: 865 case PPC::BI__builtin_vsx_xvmaddasp: 866 if (Builder.getIsFPConstrained()) 867 return Builder.CreateConstrainedFPCall(F, {X, Y, Z}); 868 else 869 return Builder.CreateCall(F, {X, Y, Z}); 870 case PPC::BI__builtin_vsx_xvnmaddadp: 871 case PPC::BI__builtin_vsx_xvnmaddasp: 872 if (Builder.getIsFPConstrained()) 873 return Builder.CreateFNeg( 874 Builder.CreateConstrainedFPCall(F, {X, Y, Z}), "neg"); 875 else 876 return Builder.CreateFNeg(Builder.CreateCall(F, {X, Y, Z}), "neg"); 877 case PPC::BI__builtin_vsx_xvmsubadp: 878 case PPC::BI__builtin_vsx_xvmsubasp: 879 if (Builder.getIsFPConstrained()) 880 return Builder.CreateConstrainedFPCall( 881 F, {X, Y, Builder.CreateFNeg(Z, "neg")}); 882 else 883 return Builder.CreateCall(F, {X, Y, Builder.CreateFNeg(Z, "neg")}); 884 case PPC::BI__builtin_ppc_fnmsub: 885 case PPC::BI__builtin_ppc_fnmsubs: 886 case PPC::BI__builtin_vsx_xvnmsubadp: 887 case PPC::BI__builtin_vsx_xvnmsubasp: 888 if (Builder.getIsFPConstrained()) 889 return Builder.CreateFNeg( 890 Builder.CreateConstrainedFPCall( 891 F, {X, Y, Builder.CreateFNeg(Z, "neg")}), 892 "neg"); 893 else 894 return Builder.CreateCall( 895 CGM.getIntrinsic(Intrinsic::ppc_fnmsub, ResultType), {X, Y, Z}); 896 } 897 llvm_unreachable("Unknown FMA operation"); 898 return nullptr; // Suppress no-return warning 899 } 900 901 case PPC::BI__builtin_vsx_insertword: { 902 Value *Op0 = EmitScalarExpr(E->getArg(0)); 903 Value *Op1 = EmitScalarExpr(E->getArg(1)); 904 Value *Op2 = EmitScalarExpr(E->getArg(2)); 905 llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_vsx_xxinsertw); 906 907 // Third argument is a compile time constant int. It must be clamped to 908 // to the range [0, 12]. 909 ConstantInt *ArgCI = dyn_cast<ConstantInt>(Op2); 910 assert(ArgCI && 911 "Third arg to xxinsertw intrinsic must be constant integer"); 912 const int64_t MaxIndex = 12; 913 int64_t Index = std::clamp(ArgCI->getSExtValue(), (int64_t)0, MaxIndex); 914 915 // The builtin semantics don't exactly match the xxinsertw instructions 916 // semantics (which ppc_vsx_xxinsertw follows). The builtin extracts the 917 // word from the first argument, and inserts it in the second argument. The 918 // instruction extracts the word from its second input register and inserts 919 // it into its first input register, so swap the first and second arguments. 920 std::swap(Op0, Op1); 921 922 // Need to cast the second argument from a vector of unsigned int to a 923 // vector of long long. 924 Op1 = Builder.CreateBitCast(Op1, llvm::FixedVectorType::get(Int64Ty, 2)); 925 926 if (getTarget().isLittleEndian()) { 927 // Reverse the double words in the vector we will extract from. 928 Op0 = Builder.CreateBitCast(Op0, llvm::FixedVectorType::get(Int64Ty, 2)); 929 Op0 = Builder.CreateShuffleVector(Op0, Op0, {1, 0}); 930 931 // Reverse the index. 932 Index = MaxIndex - Index; 933 } 934 935 // Intrinsic expects the first arg to be a vector of int. 936 Op0 = Builder.CreateBitCast(Op0, llvm::FixedVectorType::get(Int32Ty, 4)); 937 Op2 = ConstantInt::getSigned(Int32Ty, Index); 938 return Builder.CreateCall(F, {Op0, Op1, Op2}); 939 } 940 941 case PPC::BI__builtin_vsx_extractuword: { 942 Value *Op0 = EmitScalarExpr(E->getArg(0)); 943 Value *Op1 = EmitScalarExpr(E->getArg(1)); 944 llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_vsx_xxextractuw); 945 946 // Intrinsic expects the first argument to be a vector of doublewords. 947 Op0 = Builder.CreateBitCast(Op0, llvm::FixedVectorType::get(Int64Ty, 2)); 948 949 // The second argument is a compile time constant int that needs to 950 // be clamped to the range [0, 12]. 951 ConstantInt *ArgCI = dyn_cast<ConstantInt>(Op1); 952 assert(ArgCI && 953 "Second Arg to xxextractuw intrinsic must be a constant integer!"); 954 const int64_t MaxIndex = 12; 955 int64_t Index = std::clamp(ArgCI->getSExtValue(), (int64_t)0, MaxIndex); 956 957 if (getTarget().isLittleEndian()) { 958 // Reverse the index. 959 Index = MaxIndex - Index; 960 Op1 = ConstantInt::getSigned(Int32Ty, Index); 961 962 // Emit the call, then reverse the double words of the results vector. 963 Value *Call = Builder.CreateCall(F, {Op0, Op1}); 964 965 Value *ShuffleCall = 966 Builder.CreateShuffleVector(Call, Call, {1, 0}); 967 return ShuffleCall; 968 } else { 969 Op1 = ConstantInt::getSigned(Int32Ty, Index); 970 return Builder.CreateCall(F, {Op0, Op1}); 971 } 972 } 973 974 case PPC::BI__builtin_vsx_xxpermdi: { 975 Value *Op0 = EmitScalarExpr(E->getArg(0)); 976 Value *Op1 = EmitScalarExpr(E->getArg(1)); 977 Value *Op2 = EmitScalarExpr(E->getArg(2)); 978 ConstantInt *ArgCI = dyn_cast<ConstantInt>(Op2); 979 assert(ArgCI && "Third arg must be constant integer!"); 980 981 unsigned Index = ArgCI->getZExtValue(); 982 Op0 = Builder.CreateBitCast(Op0, llvm::FixedVectorType::get(Int64Ty, 2)); 983 Op1 = Builder.CreateBitCast(Op1, llvm::FixedVectorType::get(Int64Ty, 2)); 984 985 // Account for endianness by treating this as just a shuffle. So we use the 986 // same indices for both LE and BE in order to produce expected results in 987 // both cases. 988 int ElemIdx0 = (Index & 2) >> 1; 989 int ElemIdx1 = 2 + (Index & 1); 990 991 int ShuffleElts[2] = {ElemIdx0, ElemIdx1}; 992 Value *ShuffleCall = Builder.CreateShuffleVector(Op0, Op1, ShuffleElts); 993 QualType BIRetType = E->getType(); 994 auto RetTy = ConvertType(BIRetType); 995 return Builder.CreateBitCast(ShuffleCall, RetTy); 996 } 997 998 case PPC::BI__builtin_vsx_xxsldwi: { 999 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1000 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1001 Value *Op2 = EmitScalarExpr(E->getArg(2)); 1002 ConstantInt *ArgCI = dyn_cast<ConstantInt>(Op2); 1003 assert(ArgCI && "Third argument must be a compile time constant"); 1004 unsigned Index = ArgCI->getZExtValue() & 0x3; 1005 Op0 = Builder.CreateBitCast(Op0, llvm::FixedVectorType::get(Int32Ty, 4)); 1006 Op1 = Builder.CreateBitCast(Op1, llvm::FixedVectorType::get(Int32Ty, 4)); 1007 1008 // Create a shuffle mask 1009 int ElemIdx0; 1010 int ElemIdx1; 1011 int ElemIdx2; 1012 int ElemIdx3; 1013 if (getTarget().isLittleEndian()) { 1014 // Little endian element N comes from element 8+N-Index of the 1015 // concatenated wide vector (of course, using modulo arithmetic on 1016 // the total number of elements). 1017 ElemIdx0 = (8 - Index) % 8; 1018 ElemIdx1 = (9 - Index) % 8; 1019 ElemIdx2 = (10 - Index) % 8; 1020 ElemIdx3 = (11 - Index) % 8; 1021 } else { 1022 // Big endian ElemIdx<N> = Index + N 1023 ElemIdx0 = Index; 1024 ElemIdx1 = Index + 1; 1025 ElemIdx2 = Index + 2; 1026 ElemIdx3 = Index + 3; 1027 } 1028 1029 int ShuffleElts[4] = {ElemIdx0, ElemIdx1, ElemIdx2, ElemIdx3}; 1030 Value *ShuffleCall = Builder.CreateShuffleVector(Op0, Op1, ShuffleElts); 1031 QualType BIRetType = E->getType(); 1032 auto RetTy = ConvertType(BIRetType); 1033 return Builder.CreateBitCast(ShuffleCall, RetTy); 1034 } 1035 1036 case PPC::BI__builtin_pack_vector_int128: { 1037 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1038 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1039 bool isLittleEndian = getTarget().isLittleEndian(); 1040 Value *PoisonValue = 1041 llvm::PoisonValue::get(llvm::FixedVectorType::get(Op0->getType(), 2)); 1042 Value *Res = Builder.CreateInsertElement( 1043 PoisonValue, Op0, (uint64_t)(isLittleEndian ? 1 : 0)); 1044 Res = Builder.CreateInsertElement(Res, Op1, 1045 (uint64_t)(isLittleEndian ? 0 : 1)); 1046 return Builder.CreateBitCast(Res, ConvertType(E->getType())); 1047 } 1048 1049 case PPC::BI__builtin_unpack_vector_int128: { 1050 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1051 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1052 ConstantInt *Index = cast<ConstantInt>(Op1); 1053 Value *Unpacked = Builder.CreateBitCast( 1054 Op0, llvm::FixedVectorType::get(ConvertType(E->getType()), 2)); 1055 1056 if (getTarget().isLittleEndian()) 1057 Index = 1058 ConstantInt::get(Index->getIntegerType(), 1 - Index->getZExtValue()); 1059 1060 return Builder.CreateExtractElement(Unpacked, Index); 1061 } 1062 1063 case PPC::BI__builtin_ppc_sthcx: { 1064 llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_sthcx); 1065 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1066 Value *Op1 = Builder.CreateSExt(EmitScalarExpr(E->getArg(1)), Int32Ty); 1067 return Builder.CreateCall(F, {Op0, Op1}); 1068 } 1069 1070 // The PPC MMA builtins take a pointer to a __vector_quad as an argument. 1071 // Some of the MMA instructions accumulate their result into an existing 1072 // accumulator whereas the others generate a new accumulator. So we need to 1073 // use custom code generation to expand a builtin call with a pointer to a 1074 // load (if the corresponding instruction accumulates its result) followed by 1075 // the call to the intrinsic and a store of the result. 1076 #define CUSTOM_BUILTIN(Name, Intr, Types, Accumulate, Feature) \ 1077 case PPC::BI__builtin_##Name: 1078 #include "clang/Basic/BuiltinsPPC.def" 1079 { 1080 SmallVector<Value *, 4> Ops; 1081 for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) 1082 if (E->getArg(i)->getType()->isArrayType()) 1083 Ops.push_back( 1084 EmitArrayToPointerDecay(E->getArg(i)).emitRawPointer(*this)); 1085 else 1086 Ops.push_back(EmitScalarExpr(E->getArg(i))); 1087 // The first argument of these two builtins is a pointer used to store their 1088 // result. However, the llvm intrinsics return their result in multiple 1089 // return values. So, here we emit code extracting these values from the 1090 // intrinsic results and storing them using that pointer. 1091 if (BuiltinID == PPC::BI__builtin_mma_disassemble_acc || 1092 BuiltinID == PPC::BI__builtin_vsx_disassemble_pair || 1093 BuiltinID == PPC::BI__builtin_mma_disassemble_pair) { 1094 unsigned NumVecs = 2; 1095 auto Intrinsic = Intrinsic::ppc_vsx_disassemble_pair; 1096 if (BuiltinID == PPC::BI__builtin_mma_disassemble_acc) { 1097 NumVecs = 4; 1098 Intrinsic = Intrinsic::ppc_mma_disassemble_acc; 1099 } 1100 llvm::Function *F = CGM.getIntrinsic(Intrinsic); 1101 Address Addr = EmitPointerWithAlignment(E->getArg(1)); 1102 Value *Vec = Builder.CreateLoad(Addr); 1103 Value *Call = Builder.CreateCall(F, {Vec}); 1104 llvm::Type *VTy = llvm::FixedVectorType::get(Int8Ty, 16); 1105 Value *Ptr = Ops[0]; 1106 for (unsigned i=0; i<NumVecs; i++) { 1107 Value *Vec = Builder.CreateExtractValue(Call, i); 1108 llvm::ConstantInt* Index = llvm::ConstantInt::get(IntTy, i); 1109 Value *GEP = Builder.CreateInBoundsGEP(VTy, Ptr, Index); 1110 Builder.CreateAlignedStore(Vec, GEP, MaybeAlign(16)); 1111 } 1112 return Call; 1113 } 1114 if (BuiltinID == PPC::BI__builtin_vsx_build_pair || 1115 BuiltinID == PPC::BI__builtin_mma_build_acc) { 1116 // Reverse the order of the operands for LE, so the 1117 // same builtin call can be used on both LE and BE 1118 // without the need for the programmer to swap operands. 1119 // The operands are reversed starting from the second argument, 1120 // the first operand is the pointer to the pair/accumulator 1121 // that is being built. 1122 if (getTarget().isLittleEndian()) 1123 std::reverse(Ops.begin() + 1, Ops.end()); 1124 } 1125 bool Accumulate; 1126 switch (BuiltinID) { 1127 #define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ 1128 case PPC::BI__builtin_##Name: \ 1129 ID = Intrinsic::ppc_##Intr; \ 1130 Accumulate = Acc; \ 1131 break; 1132 #include "clang/Basic/BuiltinsPPC.def" 1133 } 1134 if (BuiltinID == PPC::BI__builtin_vsx_lxvp || 1135 BuiltinID == PPC::BI__builtin_vsx_stxvp || 1136 BuiltinID == PPC::BI__builtin_mma_lxvp || 1137 BuiltinID == PPC::BI__builtin_mma_stxvp) { 1138 if (BuiltinID == PPC::BI__builtin_vsx_lxvp || 1139 BuiltinID == PPC::BI__builtin_mma_lxvp) { 1140 Ops[0] = Builder.CreateGEP(Int8Ty, Ops[1], Ops[0]); 1141 } else { 1142 Ops[1] = Builder.CreateGEP(Int8Ty, Ops[2], Ops[1]); 1143 } 1144 Ops.pop_back(); 1145 llvm::Function *F = CGM.getIntrinsic(ID); 1146 return Builder.CreateCall(F, Ops, ""); 1147 } 1148 SmallVector<Value*, 4> CallOps; 1149 if (Accumulate) { 1150 Address Addr = EmitPointerWithAlignment(E->getArg(0)); 1151 Value *Acc = Builder.CreateLoad(Addr); 1152 CallOps.push_back(Acc); 1153 } 1154 for (unsigned i=1; i<Ops.size(); i++) 1155 CallOps.push_back(Ops[i]); 1156 llvm::Function *F = CGM.getIntrinsic(ID); 1157 Value *Call = Builder.CreateCall(F, CallOps); 1158 return Builder.CreateAlignedStore(Call, Ops[0], MaybeAlign()); 1159 } 1160 1161 case PPC::BI__builtin_ppc_compare_and_swap: 1162 case PPC::BI__builtin_ppc_compare_and_swaplp: { 1163 Address Addr = EmitPointerWithAlignment(E->getArg(0)); 1164 Address OldValAddr = EmitPointerWithAlignment(E->getArg(1)); 1165 Value *OldVal = Builder.CreateLoad(OldValAddr); 1166 QualType AtomicTy = E->getArg(0)->getType()->getPointeeType(); 1167 LValue LV = MakeAddrLValue(Addr, AtomicTy); 1168 Value *Op2 = EmitScalarExpr(E->getArg(2)); 1169 auto Pair = EmitAtomicCompareExchange( 1170 LV, RValue::get(OldVal), RValue::get(Op2), E->getExprLoc(), 1171 llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Monotonic, true); 1172 // Unlike c11's atomic_compare_exchange, according to 1173 // https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=functions-compare-swap-compare-swaplp 1174 // > In either case, the contents of the memory location specified by addr 1175 // > are copied into the memory location specified by old_val_addr. 1176 // But it hasn't specified storing to OldValAddr is atomic or not and 1177 // which order to use. Now following XL's codegen, treat it as a normal 1178 // store. 1179 Value *LoadedVal = Pair.first.getScalarVal(); 1180 Builder.CreateStore(LoadedVal, OldValAddr); 1181 return Builder.CreateZExt(Pair.second, Builder.getInt32Ty()); 1182 } 1183 case PPC::BI__builtin_ppc_fetch_and_add: 1184 case PPC::BI__builtin_ppc_fetch_and_addlp: { 1185 return MakeBinaryAtomicValue(*this, AtomicRMWInst::Add, E, 1186 llvm::AtomicOrdering::Monotonic); 1187 } 1188 case PPC::BI__builtin_ppc_fetch_and_and: 1189 case PPC::BI__builtin_ppc_fetch_and_andlp: { 1190 return MakeBinaryAtomicValue(*this, AtomicRMWInst::And, E, 1191 llvm::AtomicOrdering::Monotonic); 1192 } 1193 1194 case PPC::BI__builtin_ppc_fetch_and_or: 1195 case PPC::BI__builtin_ppc_fetch_and_orlp: { 1196 return MakeBinaryAtomicValue(*this, AtomicRMWInst::Or, E, 1197 llvm::AtomicOrdering::Monotonic); 1198 } 1199 case PPC::BI__builtin_ppc_fetch_and_swap: 1200 case PPC::BI__builtin_ppc_fetch_and_swaplp: { 1201 return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xchg, E, 1202 llvm::AtomicOrdering::Monotonic); 1203 } 1204 case PPC::BI__builtin_ppc_ldarx: 1205 case PPC::BI__builtin_ppc_lwarx: 1206 case PPC::BI__builtin_ppc_lharx: 1207 case PPC::BI__builtin_ppc_lbarx: 1208 return emitPPCLoadReserveIntrinsic(*this, BuiltinID, E); 1209 case PPC::BI__builtin_ppc_mfspr: { 1210 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1211 llvm::Type *RetType = CGM.getDataLayout().getTypeSizeInBits(VoidPtrTy) == 32 1212 ? Int32Ty 1213 : Int64Ty; 1214 Function *F = CGM.getIntrinsic(Intrinsic::ppc_mfspr, RetType); 1215 return Builder.CreateCall(F, {Op0}); 1216 } 1217 case PPC::BI__builtin_ppc_mtspr: { 1218 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1219 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1220 llvm::Type *RetType = CGM.getDataLayout().getTypeSizeInBits(VoidPtrTy) == 32 1221 ? Int32Ty 1222 : Int64Ty; 1223 Function *F = CGM.getIntrinsic(Intrinsic::ppc_mtspr, RetType); 1224 return Builder.CreateCall(F, {Op0, Op1}); 1225 } 1226 case PPC::BI__builtin_ppc_popcntb: { 1227 Value *ArgValue = EmitScalarExpr(E->getArg(0)); 1228 llvm::Type *ArgType = ArgValue->getType(); 1229 Function *F = CGM.getIntrinsic(Intrinsic::ppc_popcntb, {ArgType, ArgType}); 1230 return Builder.CreateCall(F, {ArgValue}, "popcntb"); 1231 } 1232 case PPC::BI__builtin_ppc_mtfsf: { 1233 // The builtin takes a uint32 that needs to be cast to an 1234 // f64 to be passed to the intrinsic. 1235 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1236 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1237 Value *Cast = Builder.CreateUIToFP(Op1, DoubleTy); 1238 llvm::Function *F = CGM.getIntrinsic(Intrinsic::ppc_mtfsf); 1239 return Builder.CreateCall(F, {Op0, Cast}, ""); 1240 } 1241 1242 case PPC::BI__builtin_ppc_swdiv_nochk: 1243 case PPC::BI__builtin_ppc_swdivs_nochk: { 1244 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1245 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1246 FastMathFlags FMF = Builder.getFastMathFlags(); 1247 Builder.getFastMathFlags().setFast(); 1248 Value *FDiv = Builder.CreateFDiv(Op0, Op1, "swdiv_nochk"); 1249 Builder.getFastMathFlags() &= (FMF); 1250 return FDiv; 1251 } 1252 case PPC::BI__builtin_ppc_fric: 1253 return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( 1254 *this, E, Intrinsic::rint, 1255 Intrinsic::experimental_constrained_rint)) 1256 .getScalarVal(); 1257 case PPC::BI__builtin_ppc_frim: 1258 case PPC::BI__builtin_ppc_frims: 1259 return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( 1260 *this, E, Intrinsic::floor, 1261 Intrinsic::experimental_constrained_floor)) 1262 .getScalarVal(); 1263 case PPC::BI__builtin_ppc_frin: 1264 case PPC::BI__builtin_ppc_frins: 1265 return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( 1266 *this, E, Intrinsic::round, 1267 Intrinsic::experimental_constrained_round)) 1268 .getScalarVal(); 1269 case PPC::BI__builtin_ppc_frip: 1270 case PPC::BI__builtin_ppc_frips: 1271 return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( 1272 *this, E, Intrinsic::ceil, 1273 Intrinsic::experimental_constrained_ceil)) 1274 .getScalarVal(); 1275 case PPC::BI__builtin_ppc_friz: 1276 case PPC::BI__builtin_ppc_frizs: 1277 return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( 1278 *this, E, Intrinsic::trunc, 1279 Intrinsic::experimental_constrained_trunc)) 1280 .getScalarVal(); 1281 case PPC::BI__builtin_ppc_fsqrt: 1282 case PPC::BI__builtin_ppc_fsqrts: 1283 return RValue::get(emitUnaryMaybeConstrainedFPBuiltin( 1284 *this, E, Intrinsic::sqrt, 1285 Intrinsic::experimental_constrained_sqrt)) 1286 .getScalarVal(); 1287 case PPC::BI__builtin_ppc_test_data_class: { 1288 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1289 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1290 return Builder.CreateCall( 1291 CGM.getIntrinsic(Intrinsic::ppc_test_data_class, Op0->getType()), 1292 {Op0, Op1}, "test_data_class"); 1293 } 1294 case PPC::BI__builtin_ppc_maxfe: { 1295 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1296 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1297 Value *Op2 = EmitScalarExpr(E->getArg(2)); 1298 Value *Op3 = EmitScalarExpr(E->getArg(3)); 1299 return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_maxfe), 1300 {Op0, Op1, Op2, Op3}); 1301 } 1302 case PPC::BI__builtin_ppc_maxfl: { 1303 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1304 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1305 Value *Op2 = EmitScalarExpr(E->getArg(2)); 1306 Value *Op3 = EmitScalarExpr(E->getArg(3)); 1307 return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_maxfl), 1308 {Op0, Op1, Op2, Op3}); 1309 } 1310 case PPC::BI__builtin_ppc_maxfs: { 1311 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1312 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1313 Value *Op2 = EmitScalarExpr(E->getArg(2)); 1314 Value *Op3 = EmitScalarExpr(E->getArg(3)); 1315 return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_maxfs), 1316 {Op0, Op1, Op2, Op3}); 1317 } 1318 case PPC::BI__builtin_ppc_minfe: { 1319 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1320 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1321 Value *Op2 = EmitScalarExpr(E->getArg(2)); 1322 Value *Op3 = EmitScalarExpr(E->getArg(3)); 1323 return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_minfe), 1324 {Op0, Op1, Op2, Op3}); 1325 } 1326 case PPC::BI__builtin_ppc_minfl: { 1327 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1328 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1329 Value *Op2 = EmitScalarExpr(E->getArg(2)); 1330 Value *Op3 = EmitScalarExpr(E->getArg(3)); 1331 return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_minfl), 1332 {Op0, Op1, Op2, Op3}); 1333 } 1334 case PPC::BI__builtin_ppc_minfs: { 1335 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1336 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1337 Value *Op2 = EmitScalarExpr(E->getArg(2)); 1338 Value *Op3 = EmitScalarExpr(E->getArg(3)); 1339 return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_minfs), 1340 {Op0, Op1, Op2, Op3}); 1341 } 1342 case PPC::BI__builtin_ppc_swdiv: 1343 case PPC::BI__builtin_ppc_swdivs: { 1344 Value *Op0 = EmitScalarExpr(E->getArg(0)); 1345 Value *Op1 = EmitScalarExpr(E->getArg(1)); 1346 return Builder.CreateFDiv(Op0, Op1, "swdiv"); 1347 } 1348 case PPC::BI__builtin_ppc_set_fpscr_rn: 1349 return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_setrnd), 1350 {EmitScalarExpr(E->getArg(0))}); 1351 case PPC::BI__builtin_ppc_mffs: 1352 return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::ppc_readflm)); 1353 } 1354 } 1355