Skip to content

Commit 7e54ae2

Browse files
authored
[mlir][llvm] Do not inline variadic functions (#77241)
This revision updates the llvm dialect inliner to explicitly disallow the inlining of variadic functions. Already previously the inlining failed if the number of function arguments did not match the number of call arguments. After the change, inlining checks the function is not variadic and it does not contain a va_start intrinsic.
1 parent bae1fde commit 7e54ae2

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

mlir/lib/Dialect/LLVMIR/IR/LLVMInlining.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,10 @@ struct LLVMInlinerInterface : public DialectInlinerInterface {
663663
<< "Cannot inline: callable is not an LLVM::LLVMFuncOp\n");
664664
return false;
665665
}
666+
if (funcOp.isVarArg()) {
667+
LLVM_DEBUG(llvm::dbgs() << "Cannot inline: callable is variadic\n");
668+
return false;
669+
}
666670
// TODO: Generate aliasing metadata from noalias argument/result attributes.
667671
if (auto attrs = funcOp.getArgAttrs()) {
668672
for (DictionaryAttr attrDict : attrs->getAsRange<DictionaryAttr>()) {
@@ -704,7 +708,8 @@ struct LLVMInlinerInterface : public DialectInlinerInterface {
704708
}
705709

706710
bool isLegalToInline(Operation *op, Region *, bool, IRMapping &) const final {
707-
return true;
711+
// The inliner cannot handle variadic function arguments.
712+
return !isa<LLVM::VaStartOp>(op);
708713
}
709714

710715
/// Handle the given inlined return by replacing it with a branch. This

mlir/test/Dialect/LLVMIR/inlining.mlir

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,3 +644,28 @@ llvm.func @caller(%ptr : !llvm.ptr) -> i32 {
644644
llvm.store %c5, %ptr { access_groups = [#caller] } : i32, !llvm.ptr
645645
llvm.return %0 : i32
646646
}
647+
648+
// -----
649+
650+
llvm.func @vararg_func(...) {
651+
llvm.return
652+
}
653+
654+
llvm.func @vararg_intrinrics() {
655+
%0 = llvm.mlir.constant(1 : i32) : i32
656+
%list = llvm.alloca %0 x !llvm.struct<"struct.va_list_opaque", (ptr)> : (i32) -> !llvm.ptr
657+
// The vararg intinriscs should normally be part of a variadic function.
658+
// However, this test uses a non-variadic function to ensure the presence of
659+
// the intrinsic alone suffices to prevent inlining.
660+
llvm.intr.vastart %list : !llvm.ptr
661+
llvm.return
662+
}
663+
664+
// CHECK-LABEL: func @caller
665+
llvm.func @caller() {
666+
// CHECK-NEXT: llvm.call @vararg_func()
667+
llvm.call @vararg_func() vararg(!llvm.func<void (...)>) : () -> ()
668+
// CHECK-NEXT: llvm.call @vararg_intrinrics()
669+
llvm.call @vararg_intrinrics() : () -> ()
670+
llvm.return
671+
}

0 commit comments

Comments
 (0)