Skip to content

[TLI] Add getLibFunc that accepts an Opcode and scalar Type. #75919

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 21, 2023

Conversation

paschalis-mpeis
Copy link
Member

@paschalis-mpeis paschalis-mpeis commented Dec 19, 2023

It sets a LibFunc similarly with the other two getLibFunc methods. Currently, it supports only the FRem Instruction.

Add tests for FRem.

Motivation:

Almost all libm functions are represented in LLVM as intrinsics with the exception of fmod that is transformed into the FREM Instruction. This difference means existing code to map scalar calls to vector functions (as used by LoopVectorize and ReplaceWithVecLib) does not work and so first we want to map the instruction back to it’s representative scalar function.

Given variants of getLibFunc exist to map an intrinsic to such functions it seems reasonable to have a variant for instructions as well.

@llvmbot llvmbot added the llvm:analysis Includes value tracking, cost tables and constant folding label Dec 19, 2023
@llvmbot
Copy link
Member

llvmbot commented Dec 19, 2023

@llvm/pr-subscribers-llvm-analysis

Author: Paschalis Mpeis (paschalis-mpeis)

Changes

It sets a LibFunc similarly with the other two getLibFunc methods. Currently, it supports only the FRem Instruction.

Add tests for FRem.


Full diff: https://github.com/llvm/llvm-project/pull/75919.diff

3 Files Affected:

  • (modified) llvm/include/llvm/Analysis/TargetLibraryInfo.h (+10)
  • (modified) llvm/lib/Analysis/TargetLibraryInfo.cpp (+16)
  • (modified) llvm/unittests/Analysis/TargetLibraryInfoTest.cpp (+61)
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
index 2ffd4d4b714394..bd77d1e8285626 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
@@ -156,6 +156,10 @@ class TargetLibraryInfoImpl {
   /// FDecl is assumed to have a parent Module when using this function.
   bool getLibFunc(const Function &FDecl, LibFunc &F) const;
 
+  /// Searches for a function name using the opcode of \p I. Currently, only the
+  /// frem instruction is supported.
+  bool getLibFunc(const Instruction &I, LibFunc &F) const;
+
   /// Forces a function to be marked as unavailable.
   void setUnavailable(LibFunc F) {
     setState(F, Unavailable);
@@ -360,6 +364,12 @@ class TargetLibraryInfo {
            getLibFunc(*(CB.getCalledFunction()), F);
   }
 
+  /// Searches for a function name using the opcode of \p I. Currently, only the
+  /// frem instruction is supported.
+  bool getLibFunc(const Instruction &I, LibFunc &F) const {
+    return Impl->getLibFunc(I, F);
+  }
+
   /// Disables all builtins.
   ///
   /// This can be used for options like -fno-builtin.
diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index 20959cf6948f65..4bc9db2db54258 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -1149,6 +1149,22 @@ bool TargetLibraryInfoImpl::getLibFunc(const Function &FDecl,
   return isValidProtoForLibFunc(*FDecl.getFunctionType(), F, *M);
 }
 
+bool TargetLibraryInfoImpl::getLibFunc(const Instruction &I, LibFunc &F) const {
+  if (I.getOpcode() != Instruction::FRem)
+    return false;
+
+  Type *ScalarTy = I.getType()->getScalarType();
+  if (ScalarTy->isDoubleTy())
+    F = LibFunc_fmod;
+  else if (ScalarTy->isFloatTy())
+    F = LibFunc_fmodf;
+  else if (ScalarTy->isFP128Ty())
+    F = LibFunc_fmodl;
+  else
+    return false;
+  return true;
+}
+
 void TargetLibraryInfoImpl::disableAllFunctions() {
   memset(AvailableArray, 0, sizeof(AvailableArray));
 }
diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index 292b5cade9509b..d4285092a58d3c 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/SourceMgr.h"
@@ -621,3 +622,63 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
     EXPECT_TRUE(isLibFunc(F, LF));
   }
 }
+
+namespace {
+
+// Creates TLI for AArch64 and VecLibrary ARmPL, and uses it to get the TLI
+// names for different FRem Instructions.
+class TLITestAarch64ArmPl : public ::testing::Test {
+private:
+  SMDiagnostic Err;
+  const Triple TargetTriple;
+  const TargetLibraryInfoImpl::VectorLibrary VecLib;
+
+protected:
+  LLVMContext Ctx;
+  std::unique_ptr<Module> M;
+  std::unique_ptr<TargetLibraryInfoImpl> TLII;
+  std::unique_ptr<TargetLibraryInfo> TLI;
+
+  /// Create TLI for AArch64 with VecLib ArmPL.
+  TLITestAarch64ArmPl()
+      : TargetTriple(Triple("aarch64-unknown-linux-gnu")),
+        VecLib(TargetLibraryInfoImpl::ArmPL) {
+    TLII = std::make_unique<TargetLibraryInfoImpl>(
+        TargetLibraryInfoImpl(TargetTriple));
+    TLII->addVectorizableFunctionsFromVecLib(VecLib, TargetTriple);
+    TLI = std::make_unique<TargetLibraryInfo>(TargetLibraryInfo(*TLII));
+    // Create a dummy module needed for tests.
+    M = parseAssemblyString("declare void @dummy()", Err, Ctx);
+    EXPECT_NE(M.get(), nullptr)
+        << "Loading an invalid module.\n " << Err.getMessage() << "\n";
+  }
+
+  /// Creates an FRem Instruction of Type \p Ty, and uses it to get the TLI
+  /// function name.
+  StringRef getFremScalarName(Type *Ty) {
+    // Use a dummy function and a BB to create an FRem Instruction.
+    FunctionType *FTy = FunctionType::get(Ty, {Ty, Ty}, false);
+    Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", *M);
+    BasicBlock *BB = BasicBlock::Create(Ctx, "entry", F);
+    IRBuilder<> Builder(BB);
+    Builder.SetInsertPoint(BB);
+    auto *FRem =
+        dyn_cast<Instruction>(Builder.CreateFRem(F->getArg(0), F->getArg(1)));
+
+    // Use TLI to get LibFunc and then the TLI name.
+    LibFunc Func;
+    if (!TLI->getLibFunc(*FRem, Func))
+      return "";
+    auto FuncName = TLI->getName(Func);
+    // Erase tmp function to prepare for the next test.
+    F->eraseFromParent();
+    return FuncName;
+  }
+};
+} // end anonymous namespace
+
+TEST_F(TLITestAarch64ArmPl, TestFrem) {
+  EXPECT_EQ(getFremScalarName(Type::getDoubleTy(Ctx)), "fmod");
+  EXPECT_EQ(getFremScalarName(Type::getFloatTy(Ctx)), "fmodf");
+  EXPECT_EQ(getFremScalarName(Type::getFP128Ty(Ctx)), "fmodl");
+}
\ No newline at end of file

@nikic
Copy link
Contributor

nikic commented Dec 19, 2023

What's the motivation for this?

@paschalis-mpeis
Copy link
Member Author

paschalis-mpeis commented Dec 19, 2023

What's the motivation for this?

@nikic, almost all libm functions are represented in LLVM as intrinsics with the exception of fmod that is transformed into the FREM instruction. This difference means existing code to map scalar calls to vector functions (as used by LoopVectorize and ReplaceWithVecLib) does not work and so first we want to map the instruction back to it’s representative scalar function. Given variants of getLibFunc exist to map an intrinsic to such functions it seems reasonable to have a variant for instructions as well.

It sets a LibFunc similarly with the other two getLibFunc methods.
Currently, it supports only the FRem Instruction.

Add tests for FRem.
Test class:
- no longer using IRBuilder to create FRem instructions
- no need to use ArmPL vector library
@paschalis-mpeis paschalis-mpeis changed the title [TLI] Add getLibFunc in TLI API that accepts an Instruction. [TLI] Add getLibFunc API that accepts an Opcode and scalar Type. Dec 20, 2023
@paschalis-mpeis paschalis-mpeis changed the title [TLI] Add getLibFunc API that accepts an Opcode and scalar Type. [TLI] Add getLibFunc that accepts an Opcode and scalar Type. Dec 20, 2023
@paschalis-mpeis paschalis-mpeis force-pushed the users/paschalis/extend-tli-for-instructions branch from b371854 to 24617b5 Compare December 20, 2023 14:17
@paschalis-mpeis
Copy link
Member Author

Addressed review with 24617b5 and rebased to main.

Copy link
Collaborator

@paulwalker-arm paulwalker-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of minor things but otherwise looks good to me.

In test no longer creating an FRem instruction.
@paschalis-mpeis paschalis-mpeis merged commit c4ff0a6 into main Dec 21, 2023
@paschalis-mpeis paschalis-mpeis deleted the users/paschalis/extend-tli-for-instructions branch December 21, 2023 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
llvm:analysis Includes value tracking, cost tables and constant folding
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants