[llvm] [LLVM][Intrinsics] Adds an API to automatically resolve overload types (PR #169007)

Durgadoss R via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 20 23:48:47 PST 2025


================
@@ -197,4 +197,169 @@ TEST(IntrinsicAttributes, TestGetFnAttributesBug) {
   AttributeSet AS = getFnAttributes(Context, experimental_guard);
   EXPECT_FALSE(AS.hasAttributes());
 }
+
+// Tests non-overloaded intrinsic declaration.
+TEST_F(IntrinsicsTest, NonOverloadedIntrinsic) {
+  Type *RetTy = Type::getVoidTy(Context);
+  SmallVector<Type *, 1> ArgTys;
+  ArgTys.push_back(Type::getInt1Ty(Context));
+
+  Function *F = Intrinsic::getOrInsertDeclaration(M.get(), Intrinsic::assume,
+                                                  RetTy, ArgTys);
+
+  ASSERT_NE(F, nullptr);
+  EXPECT_EQ(F->getIntrinsicID(), Intrinsic::assume);
+  EXPECT_EQ(F->getReturnType(), RetTy);
+  EXPECT_EQ(F->arg_size(), 1u);
+  EXPECT_FALSE(F->isVarArg());
+  EXPECT_EQ(F->getName(), "llvm.assume");
+}
+
+// Tests overloaded intrinsic with automatic type resolution for scalar types.
+TEST_F(IntrinsicsTest, OverloadedIntrinsicScalar) {
+  Type *RetTy = Type::getInt32Ty(Context);
+  SmallVector<Type *, 2> ArgTys;
+  ArgTys.push_back(Type::getInt32Ty(Context));
+  ArgTys.push_back(Type::getInt32Ty(Context));
+
+  Function *F = Intrinsic::getOrInsertDeclaration(M.get(), Intrinsic::umax,
+                                                  RetTy, ArgTys);
+
+  ASSERT_NE(F, nullptr);
+  EXPECT_EQ(F->getIntrinsicID(), Intrinsic::umax);
+  EXPECT_EQ(F->getReturnType(), RetTy);
+  EXPECT_EQ(F->arg_size(), 2u);
+  EXPECT_FALSE(F->isVarArg());
+  EXPECT_EQ(F->getName(), "llvm.umax.i32");
+}
+
+// Tests overloaded intrinsic with automatic type resolution for vector types.
+TEST_F(IntrinsicsTest, OverloadedIntrinsicVector) {
+  Type *RetTy = FixedVectorType::get(Type::getInt32Ty(Context), 4);
+  SmallVector<Type *, 2> ArgTys;
+  ArgTys.push_back(RetTy);
+  ArgTys.push_back(RetTy);
+
+  Function *F = Intrinsic::getOrInsertDeclaration(M.get(), Intrinsic::umax,
+                                                  RetTy, ArgTys);
+
+  ASSERT_NE(F, nullptr);
+  EXPECT_EQ(F->getIntrinsicID(), Intrinsic::umax);
+  EXPECT_EQ(F->getReturnType(), RetTy);
+  EXPECT_EQ(F->arg_size(), 2u);
+  EXPECT_FALSE(F->isVarArg());
+  EXPECT_EQ(F->getName(), "llvm.umax.v4i32");
+}
+
+// Tests vararg intrinsic declaration.
+TEST_F(IntrinsicsTest, VarArgIntrinsicStatepoint) {
+  Type *RetTy = Type::getTokenTy(Context);
+  SmallVector<Type *, 5> ArgTys;
+  ArgTys.push_back(Type::getInt64Ty(Context));    // ID
+  ArgTys.push_back(Type::getInt32Ty(Context));    // NumPatchBytes
+  ArgTys.push_back(PointerType::get(Context, 0)); // Target
+  ArgTys.push_back(Type::getInt32Ty(Context));    // NumCallArgs
+  ArgTys.push_back(Type::getInt32Ty(Context));    // Flags
+
+  Function *F = Intrinsic::getOrInsertDeclaration(
+      M.get(), Intrinsic::experimental_gc_statepoint, RetTy, ArgTys);
+
+  ASSERT_NE(F, nullptr);
+  EXPECT_EQ(F->getIntrinsicID(), Intrinsic::experimental_gc_statepoint);
+  EXPECT_EQ(F->getReturnType(), RetTy);
+  EXPECT_EQ(F->arg_size(), 5u);
+  EXPECT_TRUE(F->isVarArg()) << "experimental_gc_statepoint must be vararg";
+  EXPECT_EQ(F->getName(), "llvm.experimental.gc.statepoint.p0");
+}
+
+// Tests that different overloads create different declarations.
+TEST_F(IntrinsicsTest, DifferentOverloads) {
+  // i32 version
+  Type *RetTy32 = Type::getInt32Ty(Context);
+  SmallVector<Type *, 2> ArgTys32;
+  ArgTys32.push_back(Type::getInt32Ty(Context));
+  ArgTys32.push_back(Type::getInt32Ty(Context));
+
+  Function *F32 = Intrinsic::getOrInsertDeclaration(M.get(), Intrinsic::umax,
+                                                    RetTy32, ArgTys32);
+
+  // i64 version
+  Type *RetTy64 = Type::getInt64Ty(Context);
+  SmallVector<Type *, 2> ArgTys64;
+  ArgTys64.push_back(Type::getInt64Ty(Context));
+  ArgTys64.push_back(Type::getInt64Ty(Context));
+
+  Function *F64 = Intrinsic::getOrInsertDeclaration(M.get(), Intrinsic::umax,
+                                                    RetTy64, ArgTys64);
+
+  EXPECT_NE(F32, F64) << "Different overloads should be different functions";
+  EXPECT_EQ(F32->getName(), "llvm.umax.i32");
+  EXPECT_EQ(F64->getName(), "llvm.umax.i64");
+}
+
+// Tests IRBuilder::CreateIntrinsic with overloaded scalar type.
+TEST_F(IntrinsicsTest, IRBuilderCreateIntrinsicScalar) {
+  IRBuilder<> Builder(BB);
+
+  Type *RetTy = Type::getInt32Ty(Context);
+  SmallVector<Value *, 2> Args;
+  Args.push_back(ConstantInt::get(Type::getInt32Ty(Context), 10));
+  Args.push_back(ConstantInt::get(Type::getInt32Ty(Context), 20));
+
+  CallInst *CI = Builder.CreateIntrinsic(RetTy, Intrinsic::umax, Args);
+
+  ASSERT_NE(CI, nullptr);
+  EXPECT_EQ(CI->getIntrinsicID(), Intrinsic::umax);
+  EXPECT_EQ(CI->getType(), RetTy);
+  EXPECT_EQ(CI->arg_size(), 2u);
+  EXPECT_FALSE(CI->getCalledFunction()->isVarArg());
+}
+
+// Tests IRBuilder::CreateIntrinsic with overloaded vector type.
----------------
durga4github wrote:

Along with tests for scalar and vector types:
can we have a test for `overloads on pointers of different addr spaces`, if we can find one in llvm:: namespace (target agnostic) ?


https://github.com/llvm/llvm-project/pull/169007


More information about the llvm-commits mailing list