[llvm] [IR] "modular-format" attribute for functions using format strings (PR #147429)

Daniel Thornburgh via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 6 13:43:57 PST 2025


https://github.com/mysterymath updated https://github.com/llvm/llvm-project/pull/147429

>From 7457381e08f53396ea6a0b6c9acfea51775c8337 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Wed, 2 Apr 2025 16:24:57 -0700
Subject: [PATCH 01/11] [IR] "modular-format" attribute for functions using
 format strings

A new InstCombine transform uses this attribute to rewrite calls to a
modular version of the implementation along with llvm.reloc.none
relocations against aspects of the implementation needed by the call.

This change only adds support for the 'float' aspect, but it also builds
the structure needed for others.

See issue #146159
---
 llvm/docs/LangRef.rst                         | 17 +++++
 .../InstCombine/InstCombineCalls.cpp          | 62 +++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index bd0337f25c758..473381f6871fa 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -2747,6 +2747,23 @@ For example:
     all arguments are not undef and not poison. Otherwise, it is undefined
     behavior.
 
+``"modular_format"="<string_idx>,<first_idx_to_check>,<modular_impl_fn>,<impl_name>,<aspects...>"``
+    This attribute indicates that the implementation is modular on a particular
+    format string argument . When the argument for a given call is constant, the
+    compiler may redirect the call to a modular implementation function
+    instead.
+
+    The compiler also emits relocations to report various aspects of the format
+    string and arguments that were present. The compiler reports an aspect by
+    issing a relocation for the symbol `<impl_name>_<aspect>``. This arranges
+    for code and data needed to support the aspect of the implementation to be
+    brought into the link to satisfy weak references in the modular
+    implemenation function.
+
+    The following aspects are currently supported:
+
+    - ``float``: The call has a floating point argument
+
 Call Site Attributes
 ----------------------
 
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 92fca90ddb88a..b8c14b0bbee5a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -19,6 +19,7 @@
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Analysis/AssumeBundleQueries.h"
 #include "llvm/Analysis/AssumptionCache.h"
@@ -4091,6 +4092,63 @@ Instruction *InstCombinerImpl::visitCallBrInst(CallBrInst &CBI) {
   return visitCallBase(CBI);
 }
 
+static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
+  if (!CI->hasFnAttr("modular-format"))
+    return nullptr;
+
+  SmallVector<StringRef> Args(
+      llvm::split(CI->getFnAttr("modular-format").getValueAsString(), ','));
+  // TODO: Examine the format argument in Args[0].
+  // TODO: Error handling
+  unsigned FirstArgIdx;
+  if (!llvm::to_integer(Args[1], FirstArgIdx))
+    return nullptr;
+  if (FirstArgIdx == 0)
+    return nullptr;
+  --FirstArgIdx;
+  StringRef FnName = Args[2];
+  StringRef ImplName = Args[3];
+  DenseSet<StringRef> Aspects(llvm::from_range,
+                              ArrayRef<StringRef>(Args).drop_front(4));
+  Module *M = CI->getModule();
+  Function *Callee = CI->getCalledFunction();
+  FunctionCallee ModularFn =
+      M->getOrInsertFunction(FnName, Callee->getFunctionType(),
+                             Callee->getAttributes().removeFnAttribute(
+                                 M->getContext(), "modular-format"));
+  CallInst *New = cast<CallInst>(CI->clone());
+  New->setCalledFunction(ModularFn);
+  New->removeFnAttr("modular-format");
+  B.Insert(New);
+
+  const auto ReferenceAspect = [&](StringRef Aspect) {
+    SmallString<20> Name = ImplName;
+    Name += '_';
+    Name += Aspect;
+    Constant *Sym =
+        M->getOrInsertGlobal(Name, Type::getInt8Ty(M->getContext()));
+    Function *RelocNoneFn =
+        Intrinsic::getOrInsertDeclaration(M, Intrinsic::reloc_none);
+    B.CreateCall(RelocNoneFn, {Sym});
+  };
+
+  if (Aspects.contains("float")) {
+    Aspects.erase("float");
+    if (llvm::any_of(
+            llvm::make_range(std::next(CI->arg_begin(), FirstArgIdx),
+                             CI->arg_end()),
+            [](Value *V) { return V->getType()->isFloatingPointTy(); }))
+      ReferenceAspect("float");
+  }
+
+  SmallVector<StringRef> UnknownAspects(Aspects.begin(), Aspects.end());
+  llvm::sort(UnknownAspects);
+  for (StringRef Request : UnknownAspects)
+    ReferenceAspect(Request);
+
+  return New;
+}
+
 Instruction *InstCombinerImpl::tryOptimizeCall(CallInst *CI) {
   if (!CI->getCalledFunction()) return nullptr;
 
@@ -4112,6 +4170,10 @@ Instruction *InstCombinerImpl::tryOptimizeCall(CallInst *CI) {
     ++NumSimplified;
     return CI->use_empty() ? CI : replaceInstUsesWith(*CI, With);
   }
+  if (Value *With = optimizeModularFormat(CI, Builder)) {
+    ++NumSimplified;
+    return CI->use_empty() ? CI : replaceInstUsesWith(*CI, With);
+  }
 
   return nullptr;
 }

>From eff81ee4270405a6b3e6292428b1b50dc2a59901 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 8 Jul 2025 15:11:42 -0700
Subject: [PATCH 02/11] issing -> issuing

---
 llvm/docs/LangRef.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 473381f6871fa..da0cebca144bc 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -2755,7 +2755,7 @@ For example:
 
     The compiler also emits relocations to report various aspects of the format
     string and arguments that were present. The compiler reports an aspect by
-    issing a relocation for the symbol `<impl_name>_<aspect>``. This arranges
+    issuing a relocation for the symbol `<impl_name>_<aspect>``. This arranges
     for code and data needed to support the aspect of the implementation to be
     brought into the link to satisfy weak references in the modular
     implemenation function.

>From 98b34f66cbbce07a34c47eec345b391ff5b37d55 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Mon, 21 Jul 2025 15:09:58 -0700
Subject: [PATCH 03/11] Emit reloc.none instinsic with metdata string arg

---
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index b8c14b0bbee5a..689ed624cff74 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -4111,11 +4111,12 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
   DenseSet<StringRef> Aspects(llvm::from_range,
                               ArrayRef<StringRef>(Args).drop_front(4));
   Module *M = CI->getModule();
+  LLVMContext &Ctx = M->getContext();
   Function *Callee = CI->getCalledFunction();
   FunctionCallee ModularFn =
       M->getOrInsertFunction(FnName, Callee->getFunctionType(),
                              Callee->getAttributes().removeFnAttribute(
-                                 M->getContext(), "modular-format"));
+                                 Ctx, "modular-format"));
   CallInst *New = cast<CallInst>(CI->clone());
   New->setCalledFunction(ModularFn);
   New->removeFnAttr("modular-format");
@@ -4125,11 +4126,10 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
     SmallString<20> Name = ImplName;
     Name += '_';
     Name += Aspect;
-    Constant *Sym =
-        M->getOrInsertGlobal(Name, Type::getInt8Ty(M->getContext()));
     Function *RelocNoneFn =
         Intrinsic::getOrInsertDeclaration(M, Intrinsic::reloc_none);
-    B.CreateCall(RelocNoneFn, {Sym});
+    B.CreateCall(RelocNoneFn,
+                 {MetadataAsValue::get(Ctx, MDString::get(Ctx, Name))});
   };
 
   if (Aspects.contains("float")) {

>From e7f3e3bc75f4953e25c29d8431538f15fa835b4d Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 22 Jul 2025 13:24:20 -0700
Subject: [PATCH 04/11] Correct modular_format to modular-format in docs

---
 llvm/docs/LangRef.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index da0cebca144bc..bd8a090eda6a8 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -2747,7 +2747,7 @@ For example:
     all arguments are not undef and not poison. Otherwise, it is undefined
     behavior.
 
-``"modular_format"="<string_idx>,<first_idx_to_check>,<modular_impl_fn>,<impl_name>,<aspects...>"``
+``"modular-format"="<string_idx>,<first_idx_to_check>,<modular_impl_fn>,<impl_name>,<aspects...>"``
     This attribute indicates that the implementation is modular on a particular
     format string argument . When the argument for a given call is constant, the
     compiler may redirect the call to a modular implementation function

>From ce06e0a241a3d1fe79fdb1c54a56c029b1efbd23 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 22 Jul 2025 13:26:20 -0700
Subject: [PATCH 05/11] Describe the semantics of the arguments copied from C
 format attr

---
 llvm/docs/LangRef.rst | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index bd8a090eda6a8..491a46a1dcca6 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -2760,6 +2760,9 @@ For example:
     brought into the link to satisfy weak references in the modular
     implemenation function.
 
+    The first two arguments have the same semantics as the arguments to the C
+    ``format`` attribute.
+
     The following aspects are currently supported:
 
     - ``float``: The call has a floating point argument

>From 6a2b269527733200db2a1c05a14b3314deb33da8 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 22 Jul 2025 13:29:09 -0700
Subject: [PATCH 06/11] Add a type arg

---
 llvm/docs/LangRef.rst                                |  6 ++++--
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 10 +++++-----
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 491a46a1dcca6..e8a5df5caa7ea 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -2747,7 +2747,7 @@ For example:
     all arguments are not undef and not poison. Otherwise, it is undefined
     behavior.
 
-``"modular-format"="<string_idx>,<first_idx_to_check>,<modular_impl_fn>,<impl_name>,<aspects...>"``
+``"modular-format"="<type>,<string_idx>,<first_idx_to_check>,<modular_impl_fn>,<impl_name>,<aspects...>"``
     This attribute indicates that the implementation is modular on a particular
     format string argument . When the argument for a given call is constant, the
     compiler may redirect the call to a modular implementation function
@@ -2760,13 +2760,15 @@ For example:
     brought into the link to satisfy weak references in the modular
     implemenation function.
 
-    The first two arguments have the same semantics as the arguments to the C
+    The first three arguments have the same semantics as the arguments to the C
     ``format`` attribute.
 
     The following aspects are currently supported:
 
     - ``float``: The call has a floating point argument
 
+
+
 Call Site Attributes
 ----------------------
 
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 689ed624cff74..d68396e8cced5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -4098,18 +4098,18 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
 
   SmallVector<StringRef> Args(
       llvm::split(CI->getFnAttr("modular-format").getValueAsString(), ','));
-  // TODO: Examine the format argument in Args[0].
+  // TODO: Make use of the first two arguments
   // TODO: Error handling
   unsigned FirstArgIdx;
-  if (!llvm::to_integer(Args[1], FirstArgIdx))
+  if (!llvm::to_integer(Args[2], FirstArgIdx))
     return nullptr;
   if (FirstArgIdx == 0)
     return nullptr;
   --FirstArgIdx;
-  StringRef FnName = Args[2];
-  StringRef ImplName = Args[3];
+  StringRef FnName = Args[3];
+  StringRef ImplName = Args[4];
   DenseSet<StringRef> Aspects(llvm::from_range,
-                              ArrayRef<StringRef>(Args).drop_front(4));
+                              ArrayRef<StringRef>(Args).drop_front(5));
   Module *M = CI->getModule();
   LLVMContext &Ctx = M->getContext();
   Function *Callee = CI->getCalledFunction();

>From f6162f55f3745c6623b319d3bcacea6bc7d0c23f Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Thu, 21 Aug 2025 14:49:14 -0700
Subject: [PATCH 07/11] llvm.reloc.none takes a GlobalValue again

This avoids avoid modifying Module in ISel
---
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index d68396e8cced5..ab5a347ca82f6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -4111,12 +4111,11 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
   DenseSet<StringRef> Aspects(llvm::from_range,
                               ArrayRef<StringRef>(Args).drop_front(5));
   Module *M = CI->getModule();
-  LLVMContext &Ctx = M->getContext();
   Function *Callee = CI->getCalledFunction();
   FunctionCallee ModularFn =
       M->getOrInsertFunction(FnName, Callee->getFunctionType(),
                              Callee->getAttributes().removeFnAttribute(
-                                 Ctx, "modular-format"));
+                                 M->getContext(), "modular-format"));
   CallInst *New = cast<CallInst>(CI->clone());
   New->setCalledFunction(ModularFn);
   New->removeFnAttr("modular-format");
@@ -4126,10 +4125,11 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
     SmallString<20> Name = ImplName;
     Name += '_';
     Name += Aspect;
+    Constant *Sym =
+        M->getOrInsertGlobal(Name, Type::getInt8Ty(M->getContext()));
     Function *RelocNoneFn =
         Intrinsic::getOrInsertDeclaration(M, Intrinsic::reloc_none);
-    B.CreateCall(RelocNoneFn,
-                 {MetadataAsValue::get(Ctx, MDString::get(Ctx, Name))});
+    B.CreateCall(RelocNoneFn, {Sym});
   };
 
   if (Aspects.contains("float")) {

>From 3ec0dfad8dafd6472a12f2383a0eca7393dbca91 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 26 Aug 2025 14:28:34 -0700
Subject: [PATCH 08/11] Add test cases and polish change

---
 llvm/docs/LangRef.rst                         |  21 ++--
 llvm/lib/IR/Verifier.cpp                      |  14 +++
 .../InstCombine/InstCombineCalls.cpp          |   8 +-
 .../Transforms/InstCombine/modular-format.ll  | 104 ++++++++++++++++++
 llvm/test/Verifier/modular-format.ll          |  41 +++++++
 5 files changed, 172 insertions(+), 16 deletions(-)
 create mode 100644 llvm/test/Transforms/InstCombine/modular-format.ll
 create mode 100644 llvm/test/Verifier/modular-format.ll

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index e8a5df5caa7ea..b2a69dc3f3fea 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -2747,18 +2747,17 @@ For example:
     all arguments are not undef and not poison. Otherwise, it is undefined
     behavior.
 
-``"modular-format"="<type>,<string_idx>,<first_idx_to_check>,<modular_impl_fn>,<impl_name>,<aspects...>"``
+``"modular-format"="<type>,<string_idx>,<first_arg_idx>,<modular_impl_fn>,<impl_name>,<aspects...>"``
     This attribute indicates that the implementation is modular on a particular
-    format string argument . When the argument for a given call is constant, the
-    compiler may redirect the call to a modular implementation function
-    instead.
-
-    The compiler also emits relocations to report various aspects of the format
-    string and arguments that were present. The compiler reports an aspect by
-    issuing a relocation for the symbol `<impl_name>_<aspect>``. This arranges
-    for code and data needed to support the aspect of the implementation to be
-    brought into the link to satisfy weak references in the modular
-    implemenation function.
+    format string argument. If the compiler can determine that not all aspects
+    of the implementation are needed, it can report which aspects were needed
+    and redirect the call to a modular implementation function instead.
+
+    The compiler reports that an implementation aspect is needed by issuing a
+    relocation for the symbol `<impl_name>_<aspect>``. This arranges for code
+    and data needed to support the aspect of the implementation to be brought
+    into the link to satisfy weak references in the modular implemenation
+    function.
 
     The first three arguments have the same semantics as the arguments to the C
     ``format`` attribute.
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index f1e473a78e3ac..baf3862c00157 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2550,6 +2550,20 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
       CheckFailed("invalid value for 'denormal-fp-math-f32' attribute: " + S,
                   V);
   }
+
+  if (auto A = Attrs.getFnAttr("modular-format"); A.isValid()) {
+    StringRef S = A.getValueAsString();
+    SmallVector<StringRef> Args;
+    S.split(Args, ',');
+    Check(Args.size() >= 5,
+          "modular-format attribute requires at least 5 arguments", V);
+    unsigned FirstArgIdx;
+    Check(!Args[2].getAsInteger(10, FirstArgIdx),
+          "modular-format attribute first arg index is not an integer", V);
+    unsigned UpperBound = FT->getNumParams() + (FT->isVarArg() ? 1 : 0);
+    Check(FirstArgIdx > 0 && FirstArgIdx <= UpperBound,
+          "modular-format attribute first arg index is out of bounds", V);
+  }
 }
 void Verifier::verifyUnknownProfileMetadata(MDNode *MD) {
   Check(MD->getNumOperands() == 2,
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index ab5a347ca82f6..c849d779dd372 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -4099,12 +4099,10 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
   SmallVector<StringRef> Args(
       llvm::split(CI->getFnAttr("modular-format").getValueAsString(), ','));
   // TODO: Make use of the first two arguments
-  // TODO: Error handling
   unsigned FirstArgIdx;
-  if (!llvm::to_integer(Args[2], FirstArgIdx))
-    return nullptr;
-  if (FirstArgIdx == 0)
-    return nullptr;
+  [[maybe_unused]] bool Error;
+  Error = Args[2].getAsInteger(10, FirstArgIdx);
+  assert(!Error && "invalid first arg index");
   --FirstArgIdx;
   StringRef FnName = Args[3];
   StringRef ImplName = Args[4];
diff --git a/llvm/test/Transforms/InstCombine/modular-format.ll b/llvm/test/Transforms/InstCombine/modular-format.ll
new file mode 100644
index 0000000000000..9b1e60bbab4f8
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/modular-format.ll
@@ -0,0 +1,104 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Test that the modular format string library call simplifier works correctly.
+;
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
+
+ at .str.int = constant [3 x i8] c"%d\00"
+ at .str.float = constant [3 x i8] c"%f\00"
+ at .str.multi = constant [6 x i8] c"%f %d\00"
+ at .str.multifp = constant [6 x i8] c"%f %f\00"
+ at .str.noargs = constant [1 x i8] c"\00"
+
+; Basic Transformation
+define void @test_basic(i32 %arg) {
+; CHECK-LABEL: @test_basic(
+; CHECK-NEXT:    call void (ptr, ...) @basic_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
+; CHECK-NEXT:    ret void
+;
+  call void (ptr, ...) @basic(ptr @.str.int, i32 %arg)
+  ret void
+}
+
+declare void @basic(ptr, ...) "modular-format"="printf,1,2,basic_mod,basic_impl" 
+; "float" Aspect - Present
+define void @test_float_present(double %arg) {
+; CHECK-LABEL: @test_float_present(
+; CHECK-NEXT:    call void (ptr, ...) @float_present_mod(ptr nonnull @.str.float, double [[ARG:%.*]])
+; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
+; CHECK-NEXT:    ret void
+;
+  call void (ptr, ...) @float_present(ptr @.str.float, double %arg)
+  ret void
+}
+
+declare void @float_present(ptr, ...) #0
+
+; Unknown Aspects
+define void @test_unknown_aspects(i32 %arg) {
+; CHECK-LABEL: @test_unknown_aspects(
+; CHECK-NEXT:    call void (ptr, ...) @unknown_aspects_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
+; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown1)
+; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown2)
+; CHECK-NEXT:    ret void
+;
+  call void (ptr, ...) @unknown_aspects(ptr @.str.int, i32 %arg)
+  ret void
+}
+
+declare void @unknown_aspects(ptr, ...) "modular-format"="printf,1,2,unknown_aspects_mod,basic_impl,unknown1,unknown2"
+
+; Multiple Aspects
+define void @test_multiple_aspects(double %arg1, i32 %arg2) {
+; CHECK-LABEL: @test_multiple_aspects(
+; CHECK-NEXT:    call void (ptr, ...) @multiple_aspects_mod(ptr nonnull @.str.multi, double [[ARG1:%.*]], i32 [[ARG2:%.*]])
+; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
+; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown)
+; CHECK-NEXT:    ret void
+;
+  call void (ptr, ...) @multiple_aspects(ptr @.str.multi, double %arg1, i32 %arg2)
+  ret void
+}
+
+declare void @multiple_aspects(ptr, ...) "modular-format"="printf,1,2,multiple_aspects_mod,basic_impl,float,unknown"
+
+; Multiple Floating-Point Arguments
+define void @test_multiple_fp_args(double %arg1, float %arg2) {
+; CHECK-LABEL: @test_multiple_fp_args(
+; CHECK-NEXT:    call void (ptr, ...) @float_present_mod(ptr nonnull @.str.multifp, double [[ARG1:%.*]], float [[ARG2:%.*]])
+; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
+; CHECK-NEXT:    ret void
+;
+  call void (ptr, ...) @multiple_fp_args(ptr @.str.multifp, double %arg1, float %arg2)
+  ret void
+}
+
+declare void @multiple_fp_args(ptr, ...) #0
+
+; No Arguments to Check
+define void @test_no_args_to_check() {
+; CHECK-LABEL: @test_no_args_to_check(
+; CHECK-NEXT:    call void (ptr, ...) @float_present_mod(ptr nonnull @.str.noargs)
+; CHECK-NEXT:    ret void
+;
+  call void (ptr, ...) @no_args_to_check(ptr @.str.noargs)
+  ret void
+}
+
+declare void @no_args_to_check(ptr, ...) #0
+
+; First argument index != 2
+define void @test_first_arg_idx(i32 %ignored, double %arg) {
+; CHECK-LABEL: @test_first_arg_idx(
+; CHECK-NEXT:    call void (i32, ptr, ...) @first_arg_idx_mod(i32 [[IGNORED:%.*]], ptr nonnull @.str.float, double [[ARG:%.*]])
+; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
+; CHECK-NEXT:    ret void
+;
+  call void (i32, ptr, ...) @first_arg_idx(i32 %ignored, ptr @.str.float, double %arg)
+  ret void
+}
+
+declare void @first_arg_idx(i32, ptr, ...) "modular-format"="printf,2,3,first_arg_idx_mod,basic_impl,float"
+
+attributes #0 = { "modular-format"="printf,1,2,float_present_mod,basic_impl,float" }
diff --git a/llvm/test/Verifier/modular-format.ll b/llvm/test/Verifier/modular-format.ll
new file mode 100644
index 0000000000000..abdd73d098be1
--- /dev/null
+++ b/llvm/test/Verifier/modular-format.ll
@@ -0,0 +1,41 @@
+; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
+
+define void @test_too_few_arguments(i32 %arg, ...) "modular-format"="printf,1,2,basic_mod" {
+  ret void
+}
+; CHECK: modular-format attribute requires at least 5 arguments
+; CHECK-NEXT: ptr @test_too_few_arguments
+
+define void @test_first_arg_index_not_integer(i32 %arg, ...) "modular-format"="printf,1,foo,basic_mod,basic_impl" {
+  ret void
+}
+; CHECK: modular-format attribute first arg index is not an integer
+; CHECK-NEXT: ptr @test_first_arg_index_not_integer
+
+define void @test_first_arg_index_zero(i32 %arg) "modular-format"="printf,1,0,basic_mod,basic_impl" {
+  ret void
+}
+; CHECK: modular-format attribute first arg index is out of bounds
+; CHECK-NEXT: ptr @test_first_arg_index_zero
+
+define void @test_first_arg_index_out_of_bounds(i32 %arg) "modular-format"="printf,1,2,basic_mod,basic_impl" {
+  ret void
+}
+; CHECK: modular-format attribute first arg index is out of bounds
+; CHECK-NEXT: ptr @test_first_arg_index_out_of_bounds
+
+define void @test_first_arg_index_out_of_bounds_varargs(i32 %arg, ...) "modular-format"="printf,1,3,basic_mod,basic_impl" {
+  ret void
+}
+; CHECK: modular-format attribute first arg index is out of bounds
+; CHECK-NEXT: ptr @test_first_arg_index_out_of_bounds_varargs
+
+; CHECK-NOT: ptr @test_first_arg_index_in_bounds
+define void @test_first_arg_index_in_bounds(i32 %arg) "modular-format"="printf,1,1,basic_mod,basic_impl" {
+  ret void
+}
+
+; CHECK-NOT: ptr @test_first_arg_index_in_bounds_varargs
+define void @test_first_arg_index_in_bounds_varargs(i32 %arg, ...) "modular-format"="printf,1,2,basic_mod,basic_impl" {
+  ret void
+}

>From 51c509a4ccb458c1bfe56b653c1e84ea8d80494b Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 9 Sep 2025 15:11:04 -0700
Subject: [PATCH 09/11] Don't transform calls unless some aspect is unneeded

---
 .../InstCombine/InstCombineCalls.cpp          | 38 +++++---
 .../Transforms/InstCombine/modular-format.ll  | 89 ++++++++++---------
 2 files changed, 69 insertions(+), 58 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index c849d779dd372..ad408c5084988 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -4106,8 +4106,28 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
   --FirstArgIdx;
   StringRef FnName = Args[3];
   StringRef ImplName = Args[4];
-  DenseSet<StringRef> Aspects(llvm::from_range,
-                              ArrayRef<StringRef>(Args).drop_front(5));
+  ArrayRef<StringRef> AllAspects = ArrayRef<StringRef>(Args).drop_front(5);
+
+  if (AllAspects.empty())
+    return nullptr;
+
+  SmallVector<StringRef> NeededAspects;
+  for (StringRef Aspect : AllAspects) {
+    if (Aspect == "float") {
+      if (llvm::any_of(
+              llvm::make_range(std::next(CI->arg_begin(), FirstArgIdx),
+                               CI->arg_end()),
+              [](Value *V) { return V->getType()->isFloatingPointTy(); }))
+        NeededAspects.push_back("float");
+    } else {
+      // Unknown aspects are always considered to be needed.
+      NeededAspects.push_back(Aspect);
+    }
+  }
+
+  if (NeededAspects.size() == AllAspects.size())
+    return nullptr;
+
   Module *M = CI->getModule();
   Function *Callee = CI->getCalledFunction();
   FunctionCallee ModularFn =
@@ -4130,18 +4150,8 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
     B.CreateCall(RelocNoneFn, {Sym});
   };
 
-  if (Aspects.contains("float")) {
-    Aspects.erase("float");
-    if (llvm::any_of(
-            llvm::make_range(std::next(CI->arg_begin(), FirstArgIdx),
-                             CI->arg_end()),
-            [](Value *V) { return V->getType()->isFloatingPointTy(); }))
-      ReferenceAspect("float");
-  }
-
-  SmallVector<StringRef> UnknownAspects(Aspects.begin(), Aspects.end());
-  llvm::sort(UnknownAspects);
-  for (StringRef Request : UnknownAspects)
+  llvm::sort(NeededAspects);
+  for (StringRef Request : NeededAspects)
     ReferenceAspect(Request);
 
   return New;
diff --git a/llvm/test/Transforms/InstCombine/modular-format.ll b/llvm/test/Transforms/InstCombine/modular-format.ll
index 9b1e60bbab4f8..f95b6c5361ae6 100644
--- a/llvm/test/Transforms/InstCombine/modular-format.ll
+++ b/llvm/test/Transforms/InstCombine/modular-format.ll
@@ -8,75 +8,58 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
 @.str.int = constant [3 x i8] c"%d\00"
 @.str.float = constant [3 x i8] c"%f\00"
 @.str.multi = constant [6 x i8] c"%f %d\00"
- at .str.multifp = constant [6 x i8] c"%f %f\00"
 @.str.noargs = constant [1 x i8] c"\00"
 
-; Basic Transformation
+; No aspects are specified, so no transformation occurs.
 define void @test_basic(i32 %arg) {
 ; CHECK-LABEL: @test_basic(
-; CHECK-NEXT:    call void (ptr, ...) @basic_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
+; CHECK-NEXT:    call void (ptr, ...) @basic(ptr nonnull @.str.int, i32 [[ARG:%.*]])
 ; CHECK-NEXT:    ret void
 ;
   call void (ptr, ...) @basic(ptr @.str.int, i32 %arg)
   ret void
 }
 
-declare void @basic(ptr, ...) "modular-format"="printf,1,2,basic_mod,basic_impl" 
-; "float" Aspect - Present
+declare void @basic(ptr, ...) #0
+
+; The "float" aspect is present and needed, so no transformation occurs.
 define void @test_float_present(double %arg) {
 ; CHECK-LABEL: @test_float_present(
-; CHECK-NEXT:    call void (ptr, ...) @float_present_mod(ptr nonnull @.str.float, double [[ARG:%.*]])
-; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
+; CHECK-NEXT:    call void (ptr, ...) @float_present(ptr nonnull @.str.float, double [[ARG:%.*]])
 ; CHECK-NEXT:    ret void
 ;
   call void (ptr, ...) @float_present(ptr @.str.float, double %arg)
   ret void
 }
 
-declare void @float_present(ptr, ...) #0
+declare void @float_present(ptr, ...) #1
 
-; Unknown Aspects
-define void @test_unknown_aspects(i32 %arg) {
-; CHECK-LABEL: @test_unknown_aspects(
-; CHECK-NEXT:    call void (ptr, ...) @unknown_aspects_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
-; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown1)
-; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown2)
-; CHECK-NEXT:    ret void
-;
-  call void (ptr, ...) @unknown_aspects(ptr @.str.int, i32 %arg)
-  ret void
-}
-
-declare void @unknown_aspects(ptr, ...) "modular-format"="printf,1,2,unknown_aspects_mod,basic_impl,unknown1,unknown2"
-
-; Multiple Aspects
-define void @test_multiple_aspects(double %arg1, i32 %arg2) {
-; CHECK-LABEL: @test_multiple_aspects(
-; CHECK-NEXT:    call void (ptr, ...) @multiple_aspects_mod(ptr nonnull @.str.multi, double [[ARG1:%.*]], i32 [[ARG2:%.*]])
-; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
-; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown)
+; The "float" aspect is present but not needed, so the call is transformed.
+define void @test_float_absent(i32 %arg) {
+; CHECK-LABEL: @test_float_absent(
+; CHECK-NEXT:    call void (ptr, ...) @float_present_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
 ; CHECK-NEXT:    ret void
 ;
-  call void (ptr, ...) @multiple_aspects(ptr @.str.multi, double %arg1, i32 %arg2)
+  call void (ptr, ...) @float_absent(ptr @.str.int, i32 %arg)
   ret void
 }
 
-declare void @multiple_aspects(ptr, ...) "modular-format"="printf,1,2,multiple_aspects_mod,basic_impl,float,unknown"
+declare void @float_absent(ptr, ...) #1
 
-; Multiple Floating-Point Arguments
-define void @test_multiple_fp_args(double %arg1, float %arg2) {
-; CHECK-LABEL: @test_multiple_fp_args(
-; CHECK-NEXT:    call void (ptr, ...) @float_present_mod(ptr nonnull @.str.multifp, double [[ARG1:%.*]], float [[ARG2:%.*]])
-; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
+; Unknown aspects are always considered needed, so no transformation occurs.
+define void @test_unknown_aspects(i32 %arg) {
+; CHECK-LABEL: @test_unknown_aspects(
+; CHECK-NEXT:    call void (ptr, ...) @unknown_aspects(ptr nonnull @.str.int, i32 [[ARG:%.*]])
 ; CHECK-NEXT:    ret void
 ;
-  call void (ptr, ...) @multiple_fp_args(ptr @.str.multifp, double %arg1, float %arg2)
+  call void (ptr, ...) @unknown_aspects(ptr @.str.int, i32 %arg)
   ret void
 }
 
-declare void @multiple_fp_args(ptr, ...) #0
+declare void @unknown_aspects(ptr, ...) #2
 
-; No Arguments to Check
+; The call has no arguments to check, so the "float" aspect is not needed and
+; the call is transformed.
 define void @test_no_args_to_check() {
 ; CHECK-LABEL: @test_no_args_to_check(
 ; CHECK-NEXT:    call void (ptr, ...) @float_present_mod(ptr nonnull @.str.noargs)
@@ -86,19 +69,37 @@ define void @test_no_args_to_check() {
   ret void
 }
 
-declare void @no_args_to_check(ptr, ...) #0
+declare void @no_args_to_check(ptr, ...) #1
 
-; First argument index != 2
+; The first argument index is not 2. The "float" aspect is needed, so no
+; transformation occurs.
 define void @test_first_arg_idx(i32 %ignored, double %arg) {
 ; CHECK-LABEL: @test_first_arg_idx(
-; CHECK-NEXT:    call void (i32, ptr, ...) @first_arg_idx_mod(i32 [[IGNORED:%.*]], ptr nonnull @.str.float, double [[ARG:%.*]])
-; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
+; CHECK-NEXT:    call void (i32, ptr, ...) @first_arg_idx(i32 [[IGNORED:%.*]], ptr nonnull @.str.float, double [[ARG:%.*]])
 ; CHECK-NEXT:    ret void
 ;
   call void (i32, ptr, ...) @first_arg_idx(i32 %ignored, ptr @.str.float, double %arg)
   ret void
 }
 
-declare void @first_arg_idx(i32, ptr, ...) "modular-format"="printf,2,3,first_arg_idx_mod,basic_impl,float"
+declare void @first_arg_idx(i32, ptr, ...) #3
+
+; One aspect ("unknown") is needed, but one ("float") is not. The call is
+; transformed, and a reference to the needed aspect is emitted.
+define void @test_partial_aspects(i32 %arg) {
+; CHECK-LABEL: @test_partial_aspects(
+; CHECK-NEXT:    call void (ptr, ...) @multiple_aspects_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
+; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown)
+; CHECK-NEXT:    ret void
+;
+  call void (ptr, ...) @partial_aspects(ptr @.str.int, i32 %arg)
+  ret void
+}
+
+declare void @partial_aspects(ptr, ...) #4
 
-attributes #0 = { "modular-format"="printf,1,2,float_present_mod,basic_impl,float" }
+attributes #0 = { "modular-format"="printf,1,2,basic_mod,basic_impl" }
+attributes #1 = { "modular-format"="printf,1,2,float_present_mod,basic_impl,float" }
+attributes #2 = { "modular-format"="printf,1,2,unknown_aspects_mod,basic_impl,unknown1,unknown2" }
+attributes #3 = { "modular-format"="printf,2,3,first_arg_idx_mod,basic_impl,float" }
+attributes #4 = { "modular-format"="printf,1,2,multiple_aspects_mod,basic_impl,float,unknown" }

>From f2f7060ecd48b1fc812742415bb56fe463e9bdee Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Thu, 16 Oct 2025 15:36:05 -0700
Subject: [PATCH 10/11] Revert "llvm.reloc.none takes a GlobalValue again"

This reverts commit 4ac826513d3f564341d91bb9bc5cbf3a53770b57.
---
 .../lib/Transforms/InstCombine/InstCombineCalls.cpp | 13 ++++++-------
 llvm/test/Transforms/InstCombine/modular-format.ll  |  2 +-
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index ad408c5084988..8e4edefec42fd 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -4129,11 +4129,11 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
     return nullptr;
 
   Module *M = CI->getModule();
+  LLVMContext &Ctx = M->getContext();
   Function *Callee = CI->getCalledFunction();
-  FunctionCallee ModularFn =
-      M->getOrInsertFunction(FnName, Callee->getFunctionType(),
-                             Callee->getAttributes().removeFnAttribute(
-                                 M->getContext(), "modular-format"));
+  FunctionCallee ModularFn = M->getOrInsertFunction(
+      FnName, Callee->getFunctionType(),
+      Callee->getAttributes().removeFnAttribute(Ctx, "modular-format"));
   CallInst *New = cast<CallInst>(CI->clone());
   New->setCalledFunction(ModularFn);
   New->removeFnAttr("modular-format");
@@ -4143,11 +4143,10 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
     SmallString<20> Name = ImplName;
     Name += '_';
     Name += Aspect;
-    Constant *Sym =
-        M->getOrInsertGlobal(Name, Type::getInt8Ty(M->getContext()));
     Function *RelocNoneFn =
         Intrinsic::getOrInsertDeclaration(M, Intrinsic::reloc_none);
-    B.CreateCall(RelocNoneFn, {Sym});
+    B.CreateCall(RelocNoneFn,
+                 {MetadataAsValue::get(Ctx, MDString::get(Ctx, Name))});
   };
 
   llvm::sort(NeededAspects);
diff --git a/llvm/test/Transforms/InstCombine/modular-format.ll b/llvm/test/Transforms/InstCombine/modular-format.ll
index f95b6c5361ae6..af45942cc33df 100644
--- a/llvm/test/Transforms/InstCombine/modular-format.ll
+++ b/llvm/test/Transforms/InstCombine/modular-format.ll
@@ -89,7 +89,7 @@ declare void @first_arg_idx(i32, ptr, ...) #3
 define void @test_partial_aspects(i32 %arg) {
 ; CHECK-LABEL: @test_partial_aspects(
 ; CHECK-NEXT:    call void (ptr, ...) @multiple_aspects_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
-; CHECK-NEXT:    call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown)
+; CHECK-NEXT:    call void @llvm.reloc.none(metadata !"basic_impl_unknown")
 ; CHECK-NEXT:    ret void
 ;
   call void (ptr, ...) @partial_aspects(ptr @.str.int, i32 %arg)

>From f0127ee6fe9bdde905de36c91595a95a284b37b0 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Thu, 6 Nov 2025 11:27:43 -0800
Subject: [PATCH 11/11] Use two semicolons for test comments

---
 .../Transforms/InstCombine/modular-format.ll  | 20 +++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/modular-format.ll b/llvm/test/Transforms/InstCombine/modular-format.ll
index af45942cc33df..d9b7b6f056f59 100644
--- a/llvm/test/Transforms/InstCombine/modular-format.ll
+++ b/llvm/test/Transforms/InstCombine/modular-format.ll
@@ -10,7 +10,7 @@ target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f3
 @.str.multi = constant [6 x i8] c"%f %d\00"
 @.str.noargs = constant [1 x i8] c"\00"
 
-; No aspects are specified, so no transformation occurs.
+;; No aspects are specified, so no transformation occurs.
 define void @test_basic(i32 %arg) {
 ; CHECK-LABEL: @test_basic(
 ; CHECK-NEXT:    call void (ptr, ...) @basic(ptr nonnull @.str.int, i32 [[ARG:%.*]])
@@ -22,7 +22,7 @@ define void @test_basic(i32 %arg) {
 
 declare void @basic(ptr, ...) #0
 
-; The "float" aspect is present and needed, so no transformation occurs.
+;; The "float" aspect is present and needed, so no transformation occurs.
 define void @test_float_present(double %arg) {
 ; CHECK-LABEL: @test_float_present(
 ; CHECK-NEXT:    call void (ptr, ...) @float_present(ptr nonnull @.str.float, double [[ARG:%.*]])
@@ -34,7 +34,7 @@ define void @test_float_present(double %arg) {
 
 declare void @float_present(ptr, ...) #1
 
-; The "float" aspect is present but not needed, so the call is transformed.
+;; The "float" aspect is present but not needed, so the call is transformed.
 define void @test_float_absent(i32 %arg) {
 ; CHECK-LABEL: @test_float_absent(
 ; CHECK-NEXT:    call void (ptr, ...) @float_present_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
@@ -46,7 +46,7 @@ define void @test_float_absent(i32 %arg) {
 
 declare void @float_absent(ptr, ...) #1
 
-; Unknown aspects are always considered needed, so no transformation occurs.
+;; Unknown aspects are always considered needed, so no transformation occurs.
 define void @test_unknown_aspects(i32 %arg) {
 ; CHECK-LABEL: @test_unknown_aspects(
 ; CHECK-NEXT:    call void (ptr, ...) @unknown_aspects(ptr nonnull @.str.int, i32 [[ARG:%.*]])
@@ -58,8 +58,8 @@ define void @test_unknown_aspects(i32 %arg) {
 
 declare void @unknown_aspects(ptr, ...) #2
 
-; The call has no arguments to check, so the "float" aspect is not needed and
-; the call is transformed.
+;; The call has no arguments to check, so the "float" aspect is not needed and
+;; the call is transformed.
 define void @test_no_args_to_check() {
 ; CHECK-LABEL: @test_no_args_to_check(
 ; CHECK-NEXT:    call void (ptr, ...) @float_present_mod(ptr nonnull @.str.noargs)
@@ -71,8 +71,8 @@ define void @test_no_args_to_check() {
 
 declare void @no_args_to_check(ptr, ...) #1
 
-; The first argument index is not 2. The "float" aspect is needed, so no
-; transformation occurs.
+;; The first argument index is not 2. The "float" aspect is needed, so no
+;; transformation occurs.
 define void @test_first_arg_idx(i32 %ignored, double %arg) {
 ; CHECK-LABEL: @test_first_arg_idx(
 ; CHECK-NEXT:    call void (i32, ptr, ...) @first_arg_idx(i32 [[IGNORED:%.*]], ptr nonnull @.str.float, double [[ARG:%.*]])
@@ -84,8 +84,8 @@ define void @test_first_arg_idx(i32 %ignored, double %arg) {
 
 declare void @first_arg_idx(i32, ptr, ...) #3
 
-; One aspect ("unknown") is needed, but one ("float") is not. The call is
-; transformed, and a reference to the needed aspect is emitted.
+;; One aspect ("unknown") is needed, but one ("float") is not. The call is
+;; transformed, and a reference to the needed aspect is emitted.
 define void @test_partial_aspects(i32 %arg) {
 ; CHECK-LABEL: @test_partial_aspects(
 ; CHECK-NEXT:    call void (ptr, ...) @multiple_aspects_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])



More information about the llvm-commits mailing list