[llvm] [CodeGen] Teach ReplaceWithVeclib split vector llvm.sincos when only sin/cos veclib mappings exist (PR #194639)
Kito Cheng via llvm-commits
llvm-commits at lists.llvm.org
Mon May 4 22:20:26 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)
----------------
kito-cheng wrote:
I tried to add new check on verifier to guard that, and seems trigger more issue, most of them are use out of date name, but some of test seems like really intentionally like https://github.com/llvm/llvm-project/blob/main/llvm/test/CodeGen/SPIRV/allow_unknown_intrinsics.ll#L31, so...I am not sure how moving forward? 1) remove/fix those invalid intrinsic with llvm. prefix or 2) just fix those test on the X86 side?
I incline to fix that on verifier and fix all, but not sure if that right direction to go.
https://github.com/llvm/llvm-project/pull/194639
More information about the llvm-commits
mailing list