[llvm-branch-commits] [clang] [CIR] Accept fixed-width vectors in x86_64 callconv lowering (PR #215118)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Aug 9 10:24:02 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangir

Author: Adam Smith (adams381)

<details>
<summary>Changes</summary>

The CallConvLowering bridge rejects a vector in a parameter or return position, so a function taking one fails the pass. It also never reads the AVX level, which is what decides whether a vector wider than 128 bits reaches a register.

A vector is accepted now where the classifier and clang size it the same way, which means a whole-byte element and a power-of-two width. Scalable vectors and the other widths stay rejected. The module's AVX level comes from the target ABI name, as `CodeGenModule` does. A classifier per level lets a target attribute raise it for one function. An ABI older than the rule pins every function back to the module's level. A direct call takes its callee's level, and an indirect call the level of the function containing it.

CIRGen records target features on a definition but not on a declaration, so a declaration carrying the attribute is classified at the module's level until [#<!-- -->214986](https://github.com/llvm/llvm-project/pull/214986) lands.

Depends on [#<!-- -->215117](https://github.com/llvm/llvm-project/pull/215117)

Assisted-by: Cursor / claude-opus-5


---

Patch is 54.34 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/215118.diff


10 Files Affected:

- (modified) clang/include/clang/CIR/Dialect/Passes.h (+3-4) 
- (modified) clang/include/clang/CIR/Dialect/Passes.td (+4) 
- (modified) clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp (+131-33) 
- (modified) clang/lib/CIR/Lowering/CIRPasses.cpp (+24-4) 
- (modified) clang/test/CIR/CodeGen/call-conv-lowering-x86_64-abi-compat.c (+56-6) 
- (added) clang/test/CIR/CodeGen/call-conv-lowering-x86_64-avx.c (+165) 
- (modified) clang/test/CIR/CodeGen/call-conv-lowering-x86_64.c (+77) 
- (modified) clang/test/CIR/Transforms/abi-lowering/x86_64-aggregate-nyi.cir (+43) 
- (modified) clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir (+43-28) 
- (modified) clang/test/CIR/Transforms/abi-lowering/x86_64-vector.cir (+69-6) 


``````````diff
diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h
index 888e7b833b1cf..6c8bec15c3838 100644
--- a/clang/include/clang/CIR/Dialect/Passes.h
+++ b/clang/include/clang/CIR/Dialect/Passes.h
@@ -36,10 +36,9 @@ std::unique_ptr<Pass> createCIREHABILoweringPass();
 std::unique_ptr<Pass> createCXXABILoweringPass();
 std::unique_ptr<Pass> createTargetLoweringPass();
 std::unique_ptr<Pass> createCallConvLoweringPass();
-std::unique_ptr<Pass>
-createCallConvLoweringPass(cir::CallConvTarget target,
-                           llvm::abi::X86AVXABILevel x86AvxAbiLevel,
-                           const llvm::abi::ABICompatInfo &x86AbiCompat);
+std::unique_ptr<Pass> createCallConvLoweringPass(
+    cir::CallConvTarget target, llvm::abi::X86AVXABILevel x86AvxAbiLevel,
+    bool x86TargetAttrAvx, const llvm::abi::ABICompatInfo &x86AbiCompat);
 std::unique_ptr<Pass> createHoistAllocasPass();
 std::unique_ptr<Pass> createLoweringPreparePass();
 std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx);
diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td
index 04ff1c92cb7f7..bc1b99da01440 100644
--- a/clang/include/clang/CIR/Dialect/Passes.td
+++ b/clang/include/clang/CIR/Dialect/Passes.td
@@ -260,6 +260,10 @@ def CallConvLowering : Pass<"cir-call-conv-lowering", "mlir::ModuleOp"> {
              clEnumValN(llvm::abi::X86AVXABILevel::AVX, "avx", "AVX"),
              clEnumValN(llvm::abi::X86AVXABILevel::AVX512, "avx512", "AVX512")
            )}]>,
+    Option<"x86TargetAttrAvx", "x86-target-attr-avx", "bool",
+           /*default=*/"true",
+           "Let a function's own target features raise its AVX ABI level "
+           "above x86-avx-abi-level">,
   ];
 }
 
diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
index 10ed3d81f8d56..a567ae220c13a 100644
--- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
@@ -47,8 +47,13 @@
 #include "llvm/ABI/FunctionInfo.h"
 #include "llvm/ABI/TargetInfo.h"
 #include "llvm/ABI/Types.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/TypeSwitch.h"
 #include "llvm/IR/CallingConv.h"
+#include "llvm/Support/MathExtras.h"
+
+#include <algorithm>
+#include <array>
 
 using namespace mlir;
 using namespace mlir::abi;
@@ -68,10 +73,11 @@ namespace {
 // SysV x86_64 classifier, and converts the result back into the
 // dialect-agnostic mlir::abi::FunctionClassification that CIRABIRewriteContext
 // consumes.  Integer (including `_BitInt` up to 128 bits) / pointer / bool /
-// floating-point scalars are handled, as are struct / union / array aggregates
-// and `_Complex`.  Vectors, packed or padded records, and a union no member of
-// which spans its declared size are reported NYI by classifyX86_64Function so
-// an unsupported signature fails the pass instead of being misclassified.
+// floating-point scalars are handled, as are struct / union / array aggregates,
+// `_Complex`, and a fixed-width vector whose width is a power of two.  Other
+// vectors, packed or padded records, and a union no member of which spans its
+// declared size are reported NYI by classifyX86_64Function so an unsupported
+// signature fails the pass instead of being misclassified.
 //===----------------------------------------------------------------------===//
 
 /// Whether a struct's declared argument-passing kind (from the module's
@@ -103,8 +109,9 @@ static llvm::Align recordDeclaredAlign(ModuleOp modOp, cir::RecordType recTy,
 /// bits (including `_BitInt` and `__int128`), pointer, bool, void, or any
 /// floating-point type.  Aggregates: a complete struct or union whose members
 /// are all themselves supported, or an array of a supported element type.
-/// Also a `_Complex` of a supported element type.  Everything else is reported
-/// NYI at the reject() choke point in classifyX86_64Function.
+/// Also a `_Complex`, or a fixed-width vector, of a supported element type.
+/// Everything else is reported NYI at the reject() choke point in
+/// classifyX86_64Function.
 static bool isSupportedType(mlir::Type ty, const DataLayout &dl) {
   // A pointer is only handled in the default address space (null) or an
   // already-lowered target address space.  A LangAddressSpaceAttr must be
@@ -135,6 +142,34 @@ static bool isSupportedType(mlir::Type ty, const DataLayout &dl) {
   }
   if (auto complexTy = dyn_cast<cir::ComplexType>(ty))
     return isSupportedType(complexTy.getElementType(), dl);
+  if (auto vecTy = dyn_cast<cir::VectorType>(ty)) {
+    // A scalable vector has no size the SysV eightbyte rules can read, and
+    // x86_64 has no calling convention for one.
+    if (vecTy.getIsScalable())
+      return false;
+    // The classifier sizes a vector as element count times element width, so
+    // an element is only usable where that width is the one clang gives it.
+    // It is not for bool (a bit to clang, a byte here), for a _BitInt narrower
+    // than a byte (clang rounds to the storage container), or for x87 long
+    // double (80 bits here against clang's 128).  A pointer is excluded for a
+    // different reason, its pointee being what abiTypeToCIR drops.
+    mlir::Type elemTy = vecTy.getElementType();
+    if (auto elemInt = dyn_cast<cir::IntType>(elemTy)) {
+      if (elemInt.getWidth() % 8)
+        return false;
+    } else if (auto elemFp = dyn_cast<cir::FPTypeInterface>(elemTy)) {
+      if (&elemFp.getFloatSemantics() == &llvm::APFloat::x87DoubleExtended())
+        return false;
+    } else {
+      return false;
+    }
+    // Clang also rounds the vector's own width up to a power of two, and the
+    // classifier branches on the exact width, so a three-char vector would be
+    // classified at 24 bits where clang uses 32.
+    if (!llvm::isPowerOf2_64(dl.getTypeSizeInBits(ty).getFixedValue()))
+      return false;
+    return isSupportedType(elemTy, dl);
+  }
   if (auto arrTy = dyn_cast<cir::ArrayType>(ty))
     return isSupportedType(arrTy.getElementType(), dl);
   if (auto recTy = dyn_cast<cir::RecordType>(ty)) {
@@ -254,6 +289,14 @@ static const llvm::abi::Type *mapCIRType(mlir::Type type,
             mapCIRType(complexTy.getElementType(), typeMapper, dl, modOp),
             llvm::Align(dl.getTypeABIAlignment(type)));
       })
+      .Case([&](cir::VectorType vecTy) {
+        // isSupportedType rejects a scalable vector, so the element count is
+        // always fixed here.
+        return tb.getVectorType(
+            mapCIRType(vecTy.getElementType(), typeMapper, dl, modOp),
+            llvm::ElementCount::getFixed(vecTy.getSize()),
+            llvm::Align(dl.getTypeABIAlignment(type)));
+      })
       .Case([&](cir::ArrayType arrTy) {
         const llvm::abi::Type *elemAbi =
             mapCIRType(arrTy.getElementType(), typeMapper, dl, modOp);
@@ -332,10 +375,10 @@ convertABIArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx,
     // type, so a non-null coerce does not by itself mean a rewrite is needed.
     const llvm::abi::Type *coerceAbi = info.getCoerceToType();
     bool isAggregate = isa_and_present<cir::RecordType, cir::ArrayType>(origTy);
-    // For a _Complex the classifier's coerce is only sometimes the natural
-    // type, so it has to be read rather than assumed.
+    // For a _Complex or a vector the classifier's coerce is only sometimes the
+    // natural type, so it has to be read rather than assumed.
     bool comparesAgainstCoerce =
-        coerceAbi && isa_and_present<cir::ComplexType>(origTy);
+        coerceAbi && isa_and_present<cir::ComplexType, cir::VectorType>(origTy);
     bool coerceIsRegisterTuple =
         isa_and_present<llvm::abi::RecordType>(coerceAbi);
     // Compare widths rather than identity: a coerce no wider than the natural
@@ -379,8 +422,7 @@ convertABIArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx,
 /// Where \p fnTy's declared parameters end and its ellipsis arguments begin.
 ///
 /// The only x86_64 rule that reads this boundary sends an unnamed vector wider
-/// than 128 bits to memory, and isSupportedType rejects every vector, so no
-/// input this bridge accepts can observe the difference.
+/// than 128 bits to memory.
 static llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy) {
   if (!fnTy.isVarArg())
     return llvm::abi::RequiredArgs::All;
@@ -463,6 +505,34 @@ static std::optional<FunctionClassification> classifyX86_64Signature(
   return fc;
 }
 
+/// The AVX level in force at \p func, following getEffectiveX86AVXABILevel in
+/// clang/lib/CodeGen/Targets/X86.cpp.  Classic reads the target attribute
+/// itself, where this reads the feature list CIRGen recorded from it.  Two
+/// consequences: a declaration gets \p base, CIRGen recording features only on
+/// definitions, and target_clones and cpu_specific will need excluding once
+/// multiversioning is implemented, classic leaving those at the module level.
+static llvm::abi::X86AVXABILevel funcAvxLevel(cir::FuncOp func,
+                                              llvm::abi::X86AVXABILevel base) {
+  auto features = func->getAttrOfType<mlir::StringAttr>("cir.target-features");
+  if (!features)
+    return base;
+  // A '-' entry disables the feature, so match a whole '+' entry rather than
+  // searching for the name.
+  auto enabled = [&](llvm::StringRef name) {
+    for (llvm::StringRef feature : llvm::split(features.getValue(), ','))
+      if (feature.consume_front("+") && feature == name)
+        return true;
+    return false;
+  };
+  // avx512f implies avx, so both entries are present.  Test the wider name
+  // first or the AVX512 branch is unreachable.
+  if (enabled("avx512f"))
+    return std::max(base, llvm::abi::X86AVXABILevel::AVX512);
+  if (enabled("avx"))
+    return std::max(base, llvm::abi::X86AVXABILevel::AVX);
+  return base;
+}
+
 /// Classify a cir.func for x86_64 SysV using the LLVM ABI library.  Returns
 /// std::nullopt and emits an NYI error if the signature uses a type the bridge
 /// does not handle yet.
@@ -632,16 +702,33 @@ void CallConvLoweringPass::runOnOperation() {
   CIRABIRewriteContext rewriteCtx(moduleOp, dl);
   SymbolTable symbolTable(moduleOp);
 
-  // For the x86_64 target, build the LLVM ABI library classifier once and
-  // reuse it (and its type mapper) across every function.
+  // A per-function target attribute can raise the AVX level, so one classifier
+  // per module would misclassify a wide vector in such a function.
+  static constexpr unsigned numAvxLevels =
+      static_cast<unsigned>(llvm::abi::X86AVXABILevel::AVX512) + 1;
+  bool isX86 = target == cir::CallConvTarget::X86_64;
   std::optional<mlir::abi::ABITypeMapper> x86TypeMapper;
-  std::unique_ptr<llvm::abi::TargetInfo> x86Target;
-  if (target == cir::CallConvTarget::X86_64) {
+  std::array<std::unique_ptr<llvm::abi::TargetInfo>, numAvxLevels> x86Targets;
+  if (isX86)
     x86TypeMapper.emplace(dl);
-    x86Target = llvm::abi::createX86_64TargetInfo(
-        x86TypeMapper->getTypeBuilder(), x86AvxAbiLevel.getValue(),
-        /*Has64BitPointers=*/true, x86AbiCompat);
-  }
+  auto x86TargetFor =
+      [&](llvm::abi::X86AVXABILevel level) -> const llvm::abi::TargetInfo & {
+    assert(static_cast<unsigned>(level) < numAvxLevels &&
+           "a new X86AVXABILevel needs a slot in x86Targets");
+    std::unique_ptr<llvm::abi::TargetInfo> &slot =
+        x86Targets[static_cast<unsigned>(level)];
+    if (!slot)
+      slot = llvm::abi::createX86_64TargetInfo(
+          x86TypeMapper->getTypeBuilder(), level,
+          /*Has64BitPointers=*/true, x86AbiCompat);
+    return *slot;
+  };
+  llvm::abi::X86AVXABILevel baseAvxLevel = x86AvxAbiLevel.getValue();
+  auto avxLevelFor = [&](cir::FuncOp func) -> llvm::abi::X86AVXABILevel {
+    if (!x86TargetAttrAvx || !func)
+      return baseAvxLevel;
+    return funcAvxLevel(func, baseAvxLevel);
+  };
 
   // Classify every cir.func up front.  No IR mutation happens here, so
   // later walks can consult any function's classification regardless of
@@ -650,8 +737,9 @@ void CallConvLoweringPass::runOnOperation() {
   bool anyFailed = false;
   moduleOp.walk([&](cir::FuncOp f) {
     std::optional<FunctionClassification> fc;
-    if (x86Target)
-      fc = classifyX86_64Function(f, dl, *x86TypeMapper, *x86Target, moduleOp);
+    if (isX86)
+      fc = classifyX86_64Function(f, dl, *x86TypeMapper,
+                                  x86TargetFor(avxLevelFor(f)), moduleOp);
     else
       fc = classifyFunction(f, dl, target, classificationAttr);
     if (!fc) {
@@ -692,7 +780,7 @@ void CallConvLoweringPass::runOnOperation() {
     // drivers the classification comes from a fixed per-function source, so
     // such a call stays short a classification and rewriteCallSite reports it.
     cir::FuncType calleeTy = callee.getFunctionType();
-    if (!x86Target || call.getNumArgOperands() <= calleeTy.getNumInputs())
+    if (!isX86 || call.getNumArgOperands() <= calleeTy.getNumInputs())
       return;
     // A callee declared without a prototype also takes more operands than it
     // declares, and the verifier allows it.  Those extra arguments are named
@@ -704,8 +792,14 @@ void CallConvLoweringPass::runOnOperation() {
       anyFailed = true;
       return;
     }
-    std::optional<FunctionClassification> fc = classifyX86_64VariadicCall(
-        call, calleeTy, dl, *x86TypeMapper, *x86Target, moduleOp);
+    // The callee's level, not the caller's: this pass rewrites the definition
+    // and its call sites from one classification, so they have to agree.
+    // Classic instead arranges every call site from the caller and reports a
+    // caller whose level disagrees with its callee in checkFunctionCallABI,
+    // which has no equivalent here yet.
+    std::optional<FunctionClassification> fc =
+        classifyX86_64VariadicCall(call, calleeTy, dl, *x86TypeMapper,
+                                   x86TargetFor(avxLevelFor(callee)), moduleOp);
     if (!fc) {
       anyFailed = true;
       return;
@@ -805,11 +899,15 @@ void CallConvLoweringPass::runOnOperation() {
     cir::FuncType funcTy = indirectCalleeType(c);
     auto classifySignature =
         [&](mlir::TypeRange argTypes) -> std::optional<FunctionClassification> {
-      if (x86Target)
-        return classifyX86_64Signature(funcTy.getReturnType(), argTypes,
-                                       requiredArgs(funcTy), ctx, dl,
-                                       *x86TypeMapper, *x86Target, moduleOp,
-                                       [&]() { return c->emitOpError(); });
+      // A callee resolved at run time carries no features of its own, so the
+      // level comes from the function containing the call, which is the
+      // declaration classic arranges every call site from.
+      if (isX86)
+        return classifyX86_64Signature(
+            funcTy.getReturnType(), argTypes, requiredArgs(funcTy), ctx, dl,
+            *x86TypeMapper,
+            x86TargetFor(avxLevelFor(c->getParentOfType<cir::FuncOp>())),
+            moduleOp, [&]() { return c->emitOpError(); });
       return withReturnVoidness(
           mlir::abi::test::classify(argTypes, funcTy.getReturnType(), dl),
           funcTy.getReturnType());
@@ -855,12 +953,12 @@ std::unique_ptr<Pass> mlir::createCallConvLoweringPass() {
   return std::make_unique<CallConvLoweringPass>();
 }
 
-std::unique_ptr<Pass>
-mlir::createCallConvLoweringPass(cir::CallConvTarget target,
-                                 llvm::abi::X86AVXABILevel x86AvxAbiLevel,
-                                 const llvm::abi::ABICompatInfo &x86AbiCompat) {
+std::unique_ptr<Pass> mlir::createCallConvLoweringPass(
+    cir::CallConvTarget target, llvm::abi::X86AVXABILevel x86AvxAbiLevel,
+    bool x86TargetAttrAvx, const llvm::abi::ABICompatInfo &x86AbiCompat) {
   CallConvLoweringOptions options;
   options.target = target;
   options.x86AvxAbiLevel = x86AvxAbiLevel;
+  options.x86TargetAttrAvx = x86TargetAttrAvx;
   return std::make_unique<CallConvLoweringPass>(options, x86AbiCompat);
 }
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp
index dad17f2ef8659..972dc6d1a4a8b 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -29,6 +29,26 @@ static CallConvTarget getCallConvTarget(const llvm::Triple &triple) {
   return CallConvTarget::None;
 }
 
+/// The AVX level the classifier uses to size a native vector.  Read from the
+/// target ABI name, as CodeGenModule does.
+static llvm::abi::X86AVXABILevel getX86AVXABILevel(llvm::StringRef abi) {
+  if (abi == "avx512")
+    return llvm::abi::X86AVXABILevel::AVX512;
+  if (abi == "avx")
+    return llvm::abi::X86AVXABILevel::AVX;
+  return llvm::abi::X86AVXABILevel::None;
+}
+
+/// Whether `__attribute__((target(...)))` on a function may raise its AVX ABI
+/// level above the command line's.  Mirrors getEffectiveX86AVXABILevel in
+/// clang/lib/CodeGen/Targets/X86.cpp, which keeps a target that opts out, and
+/// any ABI older than the rule, at the module level.
+static bool allowsX86TargetAttrAvx(const clang::ASTContext &astContext) {
+  return !astContext.getTargetInfo().getTriple().isPS() &&
+         astContext.getLangOpts().getClangABICompat() >
+             clang::LangOptions::ClangABI::Ver23;
+}
+
 /// The x86_64 ABI-compatibility flags, derived from the target and the
 /// requested compatibility version.  Every flag defaults to true in the ABI
 /// library, which is not what any target computes: Clang11Compat is false for a
@@ -95,12 +115,12 @@ runCIRToCIRPasses(mlir::ModuleOp theModule, mlir::MLIRContext &mlirContext,
     // so it must run after CXXABILowering has lowered C++ ABI types to plain
     // records the classifier can handle.  Only the x86_64 System V classifier
     // is implemented; other targets are left unchanged.
-    CallConvTarget target =
-        getCallConvTarget(astContext.getTargetInfo().getTriple());
+    const clang::TargetInfo &targetInfo = astContext.getTargetInfo();
+    CallConvTarget target = getCallConvTarget(targetInfo.getTriple());
     if (target != CallConvTarget::None)
       pm.addPass(mlir::createCallConvLoweringPass(
-          target, llvm::abi::X86AVXABILevel::None,
-          getX86ABICompatInfo(astContext)));
+          target, getX86AVXABILevel(targetInfo.getABI()),
+          allowsX86TargetAttrAvx(astContext), getX86ABICompatInfo(astContext)));
   }
 
   pm.addPass(mlir::createLoweringPreparePass(&astContext));
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-abi-compat.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-abi-compat.c
index 6a1d9a3c4d3d2..62bc030ff1579 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-abi-compat.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-abi-compat.c
@@ -1,13 +1,32 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -clangir-enable-call-conv-lowering -emit-llvm %s -o %t-cir.ll
-// RUN: FileCheck --check-prefix=LINUX-CIR --input-file=%t-cir.ll %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
-// RUN: FileCheck --check-prefix=LINUX-OGCG --input-file=%t.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +avx -fclangir -clangir-enable-call-conv-lowering -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefixes=LINUX,LINUX-CIR --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +avx -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefixes=LINUX,LINUX-OGCG --input-file=%t.ll %s
 
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fclangir -clangir-enable-call-conv-lowering -emit-llvm %s -o %t-darwin-cir.ll
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +avx -fclang-abi-compat=3.8 -fclangir -clangir-enable-call-conv-lowering -emit-llvm %s -o %t-38-cir.ll
+// RUN: FileCheck --check-prefix=LINUX38 --input-file=%t-38-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +avx -fclang-abi-compat=3.8 -emit-llvm %s -o %t-38.ll
+// RUN: FileCheck --check-prefix=LINUX38 --input-file=%t-38.ll %s
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +avx -fclang-abi-compat=9 -fclangir -clangir-enable-call-conv-lowering -emit-llvm %s -o %t-9-cir.ll
+// RUN: FileCheck...
[truncated]

``````````

</details>


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


More information about the llvm-branch-commits mailing list