[llvm] [IR] Define empty and malformed !callees semantics (PR #221550)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 7 23:16:52 PDT 2026


================
@@ -130,6 +134,192 @@ TEST_F(ModuleWithFunctionTest, InvokeInst) {
   }
 }
 
+TEST(InstructionsTest, CalleesMetadataDecoding) {
+  LLVMContext C;
+  Module M("test", C);
+  FunctionType *CalleeTy = FunctionType::get(Type::getVoidTy(C), false);
+  Function *Target0 =
+      Function::Create(CalleeTy, GlobalValue::ExternalLinkage, "target0", M);
+  Function *Target1 =
+      Function::Create(CalleeTy, GlobalValue::ExternalLinkage, "target1", M);
+
+  FunctionType *CallerTy =
+      FunctionType::get(Type::getVoidTy(C), PointerType::getUnqual(C), false);
+  Function *Caller =
+      Function::Create(CallerTy, GlobalValue::ExternalLinkage, "caller", M);
+  BasicBlock *Entry = BasicBlock::Create(C, "entry", Caller);
+  CallInst *Indirect =
+      CallInst::Create(CalleeTy, Caller->getArg(0), {}, "", Entry);
+  CallInst *Direct = CallInst::Create(Target0, {}, "", Entry);
+  InlineAsm *Asm = InlineAsm::get(CalleeTy, "", "", true);
+  CallInst *InlineAsmCall = CallInst::Create(CalleeTy, Asm, {}, "", Entry);
+  ReturnInst::Create(C, Entry);
+
+  SmallVector<Function *, 4> Callees = {Target0};
+  EXPECT_FALSE(Indirect->getCalleesMetadata(Callees));
+  EXPECT_TRUE(Callees.empty());
+
+  Indirect->setMetadata(LLVMContext::MD_callees, MDNode::get(C, {}));
+  EXPECT_TRUE(Indirect->getCalleesMetadata(Callees));
+  EXPECT_TRUE(Callees.empty());
+
+  MDBuilder MDB(C);
+  Indirect->setMetadata(LLVMContext::MD_callees,
+                        MDB.createCallees({Target0, Target1, Target0}));
+  ASSERT_TRUE(Indirect->getCalleesMetadata(Callees));
+  ASSERT_EQ(Callees.size(), 2u);
+  EXPECT_EQ(Callees[0], Target0);
+  EXPECT_EQ(Callees[1], Target1);
+
+  MDNode *Valid = MDB.createCallees({Target0});
+  Direct->setMetadata(LLVMContext::MD_callees, Valid);
+  Callees.push_back(Target1);
+  ASSERT_TRUE(Direct->getCalleesMetadata(Callees));
+  ASSERT_EQ(Callees.size(), 1u);
+  EXPECT_EQ(Callees[0], Target0);
+
+  // Decoding validates the attachment, not the identity of the called operand.
+  InlineAsmCall->setMetadata(LLVMContext::MD_callees, Valid);
+  Callees.push_back(Target1);
+  ASSERT_TRUE(InlineAsmCall->getCalleesMetadata(Callees));
----------------
mmiftahx wrote:

The inline-asm case was there to test structural decoding independently of the called operand. I agree the shared helper should also reflect the scope of the `!callees` contract. I've excluded inline asm and updated the tests to check that both empty and nonempty attachments are ignored. Direct and indirect still retain the same constraint.

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


More information about the llvm-commits mailing list