[llvm] [CodeGen] Teach ReplaceWithVeclib split vector llvm.sincos when only sin/cos veclib mappings exist (PR #194639)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Wed May 6 18:35:11 PDT 2026
================
@@ -208,19 +208,116 @@ static bool replaceWithCallToVeclib(const TargetLibraryInfo &TLI,
return true;
}
+/// Returns true when \p TLI has a vector mapping for the scalar function name
+/// \p Name at \p EC (matching either masked or unmasked variants).
+static bool hasVectorMapping(const TargetLibraryInfo &TLI, StringRef Name,
+ ElementCount EC) {
+ return TLI.getVectorMappingInfo(Name, EC, /*Masked=*/false) ||
+ TLI.getVectorMappingInfo(Name, EC, /*Masked=*/true);
+}
+
+/// Returns true when \p TLI has a vector mapping for \p IID at the given
+/// element type and \p EC.
+static bool hasIntrinsicVectorMapping(const TargetLibraryInfo &TLI,
+ Intrinsic::ID IID, Type *ScalarTy,
+ ElementCount EC, Module *M) {
+ std::string Name = Intrinsic::getName(IID, {ScalarTy}, M);
+ return hasVectorMapping(TLI, Name, EC);
+}
+
+/// If \p II is a vector llvm.sincos with no direct vector library mapping but
+/// the target does have vector mappings for both llvm.sin and llvm.cos at the
+/// same element count, replace it with separate llvm.sin and llvm.cos calls
+/// and run the standard veclib replacement on each.
+static bool trySplitVectorSinCos(const TargetLibraryInfo &TLI,
+ IntrinsicInst *II,
+ SmallVectorImpl<Instruction *> &Replaced) {
+ if (II->getIntrinsicID() != Intrinsic::sincos)
+ return false;
+ Value *Arg = II->getArgOperand(0);
+ auto *VTy = dyn_cast<VectorType>(Arg->getType());
+ if (!VTy)
+ return false;
+
+ ElementCount EC = VTy->getElementCount();
+ Type *ScalarTy = VTy->getElementType();
+ Module *M = II->getModule();
+
+ // If a vector sincos mapping exists for the intrinsic name (e.g.
+ // "llvm.sincos.f32") or for the scalar libcall name ("sincos"/"sincosf"),
+ // leave the call alone -- SelectionDAG legalization will handle it via
+ // expandMultipleResultFPLibCall when the runtime libcall impl is enabled.
+ if (hasIntrinsicVectorMapping(TLI, Intrinsic::sincos, ScalarTy, EC, M))
+ return false;
+ StringRef LibcallName;
+ if (ScalarTy->isFloatTy())
+ LibcallName = "sincosf";
+ else if (ScalarTy->isDoubleTy())
+ LibcallName = "sincos";
+ if (!LibcallName.empty() && hasVectorMapping(TLI, LibcallName, EC))
+ return false;
+
+ // Splitting is only worthwhile when both sin and cos have vector mappings.
+ if (!hasIntrinsicVectorMapping(TLI, Intrinsic::sin, ScalarTy, EC, M) ||
+ !hasIntrinsicVectorMapping(TLI, Intrinsic::cos, ScalarTy, EC, M))
+ return false;
+
+ // All users must be extractvalue with index 0 or 1; otherwise we cannot
+ // safely rewire results.
+ for (User *U : II->users()) {
+ auto *EV = dyn_cast<ExtractValueInst>(U);
+ if (!EV || EV->getNumIndices() != 1 ||
+ (EV->getIndices()[0] != 0 && EV->getIndices()[0] != 1))
+ return false;
+ }
+
+ IRBuilder<> B(II);
+ Function *SinFn =
+ Intrinsic::getOrInsertDeclaration(M, Intrinsic::sin, Arg->getType());
+ Function *CosFn =
+ Intrinsic::getOrInsertDeclaration(M, Intrinsic::cos, Arg->getType());
+ CallInst *SinCall = B.CreateCall(SinFn, {Arg}, "sin");
+ CallInst *CosCall = B.CreateCall(CosFn, {Arg}, "cos");
+ SinCall->copyFastMathFlags(II);
+ CosCall->copyFastMathFlags(II);
+
+ // Forward extractvalue uses to the new calls.
+ for (User *U : llvm::make_early_inc_range(II->users())) {
+ auto *EV = cast<ExtractValueInst>(U);
+ EV->replaceAllUsesWith(EV->getIndices()[0] == 0 ? SinCall : CosCall);
+ EV->eraseFromParent();
+ }
+
+ // Replace each new call with the vector library function.
+ if (replaceWithCallToVeclib(TLI, cast<IntrinsicInst>(SinCall)))
+ Replaced.push_back(SinCall);
+ if (replaceWithCallToVeclib(TLI, cast<IntrinsicInst>(CosCall)))
+ Replaced.push_back(CosCall);
+
+ return true;
+}
+
static bool runImpl(const TargetLibraryInfo &TLI, Function &F) {
SmallVector<Instruction *> ReplacedCalls;
for (auto &I : instructions(F)) {
- // Process only intrinsic calls that return void or a vector.
- if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
- if (II->getIntrinsicID() == Intrinsic::not_intrinsic)
- continue;
- if (!II->getType()->isVectorTy() && !II->getType()->isVoidTy())
- continue;
-
- if (replaceWithCallToVeclib(TLI, II))
- ReplacedCalls.push_back(&I);
+ auto *II = dyn_cast<IntrinsicInst>(&I);
+ if (!II || II->getIntrinsicID() == Intrinsic::not_intrinsic)
----------------
topperc wrote:
Looks like the dyn_cast only checks that the function name starts with "llvm.". It doesn't check if it is a valid intrinsic.
https://github.com/llvm/llvm-project/pull/194639
More information about the llvm-commits
mailing list