[Mlir-commits] [clang] [llvm] [mlir] [Clang][ABI][X86] Fix arg extension incompatibility with platform psABI (PR #236450)

Nikita Popov llvmlistbot at llvm.org
Thu Oct 29 04:12:03 PDT 2026


https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/236450

>From 3c3040e8ce27f9588fc137251b5c506f5cb1af63 Mon Sep 17 00:00:00 2001
From: "Liu, Chen3" <chen3.liu at intel.com>
Date: Sun, 25 Oct 2026 08:14:04 +0000
Subject: [PATCH 01/11] [X86] Always extend the integer parameters in callee

For now clang will assume the integer parameters have been sign/zero
extended in the caller, which will cause some ABI compatibility issues.

This patch adds -mextend-small-integers=<arg>, which specifies how to
handle small integer arguments.

Adds one new ConservativeExtend Kind, which means we shouldn't make any
assumptions about the caller and callee. In this case, we must do
zero/sign extension for integer parameters in caller and callee.

Adds -mextend-small-integers=<arg> option:
  none: Pass the small integer parameter directly in caller.
  conservative: Always extend small integer parameter in the caller but
    do not assume in the callee that the caller actually did the
    extension. This is the default value.
  assumed: Assume the small integer parameter has been extended in the
    caller.
  default: Use the default rule for the target.

Differential Revision: https://reviews.llvm.org/D124435
---
 clang/include/clang/Basic/CodeGenOptions.def  |  5 ++
 clang/include/clang/Basic/CodeGenOptions.h    |  7 +++
 clang/include/clang/CodeGen/CGFunctionInfo.h  | 62 ++++++++++++++-----
 clang/include/clang/Options/Options.td        | 13 +++-
 clang/lib/CodeGen/CGCall.cpp                  | 33 +++++++---
 clang/lib/CodeGen/TargetInfo.cpp              |  3 +
 clang/lib/CodeGen/Targets/X86.cpp             | 25 ++++++--
 clang/lib/Driver/ToolChains/Clang.cpp         |  7 +++
 .../CodeGen/2007-06-18-SextAttrAggregate.c    |  4 +-
 .../CodeGen/X86/integer_argument_passing.c    | 47 ++++++++++++++
 .../CodeGen/X86/x86_32-arguments-darwin.c     |  4 +-
 .../test/CodeGen/X86/x86_32-arguments-linux.c |  2 +-
 clang/test/CodeGen/X86/x86_64-arguments.c     |  2 +-
 clang/test/CodeGen/attr-noundef.cpp           |  2 +-
 clang/test/CodeGen/builtin-align.c            |  6 +-
 clang/test/CodeGen/builtins-memset-inline.c   |  6 +-
 .../catch-implicit-integer-sign-changes.c     |  6 +-
 clang/test/CodeGen/ext-int-cc.c               |  6 +-
 clang/test/CodeGen/function-attributes.c      |  8 +--
 clang/test/CodeGen/mangle-windows.c           |  2 +-
 clang/test/CodeGen/matrix-type-builtins.c     |  4 +-
 clang/test/CodeGen/matrix-type-operators.c    | 12 ++--
 clang/test/CodeGen/ms-inline-asm.c            |  2 +-
 clang/test/CodeGen/regcall.c                  |  4 +-
 clang/test/CodeGen/vectorcall.c               |  2 +-
 clang/test/CodeGenCXX/exceptions.cpp          |  2 +-
 .../CodeGenCXX/microsoft-abi-eh-cleanups.cpp  |  2 +-
 clang/test/CodeGenCXX/new-overflow.cpp        | 12 ++--
 clang/test/CodeGenCXX/virtual-bases.cpp       |  4 +-
 clang/test/CodeGenObjC/property-atomic-bool.m |  4 +-
 .../OpenMP/target_codegen_global_capture.cpp  |  8 +--
 31 files changed, 223 insertions(+), 83 deletions(-)
 create mode 100644 clang/test/CodeGen/X86/integer_argument_passing.c

diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index c8ad0eb3f302e3..76eb04fd7c38c6 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -550,6 +550,11 @@ CODEGENOPT(ZOSPPA1Name, 1, 1, Benign)
 /// FIXME: Make DebugOptions its own top-level .def file.
 #include "DebugOptions.def"
 
+/// Whether the function should extend small integer parameters: Direct,
+/// Conservative, Assumed, Default.
+ENUM_CODEGENOPT(ExtendIntegerArgs, ExtendIntegerArgsKind, 2,
+                ExtendIntegerArgsKind::Conservative)
+
 #undef CODEGENOPT
 #undef ENUM_CODEGENOPT
 #undef VALUE_CODEGENOPT
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 5e969a4309bfbd..ce0a65847b1270 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -283,6 +283,13 @@ class CodeGenOptions : public CodeGenOptionsBase {
     ForceDisable, // Always disable regardless of the target default.
   };
 
+  enum class ExtendIntegerArgsKind {
+    Direct,       // Force the use of Direct.
+    Conservative, // Force the use of ConservativeExtend.
+    Assumed,      // Force the use of Extend.
+    Default, // Use the default rule for the target, which is Extend for now.
+  };
+
   /// The code model to use (-mcmodel).
   std::string CodeModel;
 
diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h
index d9c449d78eb08f..c0ae231d568840 100644
--- a/clang/include/clang/CodeGen/CGFunctionInfo.h
+++ b/clang/include/clang/CodeGen/CGFunctionInfo.h
@@ -43,6 +43,11 @@ class ABIArgInfo {
     /// but also emit a zero/sign extension attribute.
     Extend,
 
+    /// ConservativeExtend - Valid only for integer argument types. Same as
+    /// 'Extend' but do not assume in the callee that the caller actually did
+    /// the extension
+    ConservativeExtend,
+
     /// Indirect - Pass the argument indirectly via a hidden pointer with the
     /// specified alignment (0 indicates default alignment) and address space.
     Indirect,
@@ -124,7 +129,7 @@ class ABIArgInfo {
 
   bool canHavePaddingType() const {
     return isDirect() || isExtend() || isIndirect() || isIndirectAliased() ||
-           isExpand() || isTargetSpecific();
+           isExpand() || isTargetSpecific() || isConservativeExtend();
   }
   void setPaddingType(llvm::Type *T) {
     assert(canHavePaddingType());
@@ -205,6 +210,25 @@ class ABIArgInfo {
     return AI;
   }
 
+  static ABIArgInfo getConservativeExtend(QualType Ty,
+                                          llvm::Type *T = nullptr) {
+    assert(Ty->isIntegralOrEnumerationType() && "Unexpected QualType");
+    auto AI = ABIArgInfo(ConservativeExtend);
+    AI.setCoerceToType(T);
+    AI.setPaddingType(nullptr);
+    AI.setDirectOffset(0);
+    AI.setDirectAlign(0);
+    AI.setSignExt(Ty->hasSignedIntegerRepresentation());
+    return AI;
+  }
+
+  static ABIArgInfo getConservativeExtendInReg(QualType Ty,
+                                               llvm::Type *T = nullptr) {
+    auto AI = getConservativeExtend(Ty, T);
+    AI.setInReg(true);
+    return AI;
+  }
+
   static ABIArgInfo getExtendInReg(QualType Ty, llvm::Type *T = nullptr) {
     auto AI = getExtend(Ty, T);
     AI.setInReg(true);
@@ -327,41 +351,47 @@ class ABIArgInfo {
   bool isExpand() const { return TheKind == Expand; }
   bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
   bool isTargetSpecific() const { return TheKind == TargetSpecific; }
+  bool isConservativeExtend() const { return TheKind == ConservativeExtend; }
 
   bool canHaveCoerceToType() const {
     return isDirect() || isExtend() || isCoerceAndExpand() ||
-           isTargetSpecific();
+           isTargetSpecific() || isConservativeExtend();
   }
 
-  // Direct/Extend accessors
+  // Direct/Extend/ConservativeExtend accessors
   unsigned getDirectOffset() const {
-    assert((isDirect() || isExtend() || isTargetSpecific()) &&
-           "Not a direct or extend or target specific kind");
+    assert((isDirect() || isExtend() || isTargetSpecific() ||
+            isConservativeExtend()) &&
+           "Invalid kind!");
     return DirectAttr.Offset;
   }
   void setDirectOffset(unsigned Offset) {
-    assert((isDirect() || isExtend() || isTargetSpecific()) &&
-           "Not a direct or extend or target specific kind");
+    assert((isDirect() || isExtend() || isTargetSpecific() ||
+            isConservativeExtend()) &&
+           "Invalid kind");
     DirectAttr.Offset = Offset;
   }
 
   unsigned getDirectAlign() const {
-    assert((isDirect() || isExtend() || isTargetSpecific()) &&
-           "Not a direct or extend or target specific kind");
+    assert((isDirect() || isExtend() || isTargetSpecific() ||
+            isConservativeExtend()) &&
+           "Invalid kind");
     return DirectAttr.Align;
   }
   void setDirectAlign(unsigned Align) {
-    assert((isDirect() || isExtend() || isTargetSpecific()) &&
-           "Not a direct or extend or target specific kind");
+    assert((isDirect() || isExtend() || isTargetSpecific() ||
+            isConservativeExtend()) &&
+           "Invalid kind");
     DirectAttr.Align = Align;
   }
 
   bool isSignExt() const {
-    assert(isExtend() && (SignExt + ZeroExt <= 1) && "Invalid kind / flags!");
+    assert((isExtend() || isConservativeExtend()) &&
+           (SignExt + ZeroExt <= 1) && "Invalid kind / flags!");
     return SignExt;
   }
   void setSignExt(bool SExt) {
-    assert(isExtend() && "Invalid kind!");
+    assert((isExtend() || isConservativeExtend()) && "Invalid kind!");
     SignExt = SExt;
   }
 
@@ -421,13 +451,15 @@ class ABIArgInfo {
   }
 
   bool getInReg() const {
-    assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific()) &&
+    assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific() ||
+            isConservativeExtend()) &&
            "Invalid kind!");
     return InReg;
   }
 
   void setInReg(bool IR) {
-    assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific()) &&
+    assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific() ||
+            isConservativeExtend()) &&
            "Invalid kind!");
     InReg = IR;
   }
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 4419e3cf6f98c5..7c00bada76ccf6 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5798,7 +5798,18 @@ def mzos_hlq_clang_EQ : Joined<["-"], "mzos-hlq-clang=">, MetaVarName<"<ClangHLQ
   HelpText<"High level qualifier for z/OS C++RT side deck datasets">;
 def mzos_hlq_csslib_EQ : Joined<["-"], "mzos-hlq-csslib=">, MetaVarName<"<CsslibHLQ>">,
   HelpText<"High level qualifier for z/OS CSSLIB dataset">;
-
+def mextend_small_integers_EQ : Joined<["-"], "mextend-small-integers=">,
+  Group<m_Group>, Flags<[CC1Option]>,
+  HelpText<"How to handle the small integer parameter: "
+           "'none' (Pass the small integer parameter directly in caller) | "
+           "'conservative' (Always extend small integer parameter in the caller but do not assume "
+           "in the callee that the caller actually did the extension) | "
+           "'assumed' (Assume the small integer parameter has been extened in the caller) | "
+           "'default' (Use the default rule for the target, this value is not yet supported)">,
+  Values<"none,conservative,assumed,default">,
+  NormalizedValuesScope<"CodeGenOptions::ExtendIntegerArgsKind">,
+  NormalizedValues<["Direct", "Conservative", "Assumed", "Default"]>,
+  MarshallingInfoEnum<CodeGenOpts<"ExtendIntegerArgs">, "Conservative">;
 def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group<m_Group>;
 def mno_global_merge : Flag<["-"], "mno-global-merge">, Group<m_Group>,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 9b8b0b52b66cb5..bae1a950454a4e 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1982,7 +1982,8 @@ void ClangToLLVMArgMapping::construct(const ASTContext &Context,
     switch (AI.getKind()) {
     case ABIArgInfo::TargetSpecific:
     case ABIArgInfo::Extend:
-    case ABIArgInfo::Direct: {
+    case ABIArgInfo::Direct:
+    case ABIArgInfo::ConservativeExtend: {
       // FIXME: handle sseregparm someday...
       llvm::StructType *STy = dyn_cast<llvm::StructType>(AI.getCoerceToType());
       if (AI.isDirect() && AI.getCanBeFlattened() && STy) {
@@ -2094,6 +2095,7 @@ llvm::FunctionType *CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
   case ABIArgInfo::TargetSpecific:
   case ABIArgInfo::Extend:
   case ABIArgInfo::Direct:
+  case ABIArgInfo::ConservativeExtend:
     resultType = retAI.getCoerceToType();
     break;
 
@@ -2166,7 +2168,8 @@ llvm::FunctionType *CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
       break;
     case ABIArgInfo::TargetSpecific:
     case ABIArgInfo::Extend:
-    case ABIArgInfo::Direct: {
+    case ABIArgInfo::Direct:
+    case ABIArgInfo::ConservativeExtend: {
       // Fast-isel and the optimizer generally like scalar values better than
       // FCAs, so we flatten them if this is safe to do for this argument.
       llvm::Type *argType = ArgInfo.getCoerceToType();
@@ -3033,6 +3036,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
 
   switch (RetAI.getKind()) {
   case ABIArgInfo::Extend:
+  case ABIArgInfo::ConservativeExtend:
     if (RetAI.isSignExt())
       RetAttrs.addAttribute(llvm::Attribute::SExt);
     else if (RetAI.isZeroExt())
@@ -3193,12 +3197,17 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
     // sense to do it here because parameters are so messed up.
     switch (AI.getKind()) {
     case ABIArgInfo::Extend:
-      if (AI.isSignExt())
-        Attrs.addAttribute(llvm::Attribute::SExt);
-      else if (AI.isZeroExt())
-        Attrs.addAttribute(llvm::Attribute::ZExt);
-      else
-        Attrs.addAttribute(llvm::Attribute::NoExt);
+    case ABIArgInfo::ConservativeExtend:
+      // Under ConservativeExtend, add sext/zext only on the call site; the
+      // callee does not get to assume extension.
+      if (AttrOnCallSite || AI.getKind() == ABIArgInfo::Extend) {
+        if (AI.isSignExt())
+          Attrs.addAttribute(llvm::Attribute::SExt);
+        else if (AI.isZeroExt())
+          Attrs.addAttribute(llvm::Attribute::ZExt);
+        else
+          Attrs.addAttribute(llvm::Attribute::NoExt);
+      }
       [[fallthrough]];
     case ABIArgInfo::TargetSpecific:
     case ABIArgInfo::Direct:
@@ -3615,7 +3624,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
     }
 
     case ABIArgInfo::Extend:
-    case ABIArgInfo::Direct: {
+    case ABIArgInfo::Direct:
+    case ABIArgInfo::ConservativeExtend: {
       auto AI = Fn->getArg(FirstIRArg);
       llvm::Type *LTy = ConvertType(Arg->getType());
 
@@ -4467,6 +4477,7 @@ void CodeGenFunction::EmitFunctionEpilog(
 
   case ABIArgInfo::Extend:
   case ABIArgInfo::Direct:
+  case ABIArgInfo::ConservativeExtend:
     if (RetAI.getCoerceToType() == ConvertType(RetTy) &&
         RetAI.getDirectOffset() == 0) {
       // The internal return value temp always will have pointer-to-return-type
@@ -5976,7 +5987,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
       break;
 
     case ABIArgInfo::Extend:
-    case ABIArgInfo::Direct: {
+    case ABIArgInfo::Direct:
+    case ABIArgInfo::ConservativeExtend: {
       if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) &&
           ArgInfo.getCoerceToType() == ConvertType(info_it->type) &&
           ArgInfo.getDirectOffset() == 0) {
@@ -6753,6 +6765,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
         return GetUndefRValue(RetTy);
 
       case ABIArgInfo::Extend:
+      case ABIArgInfo::ConservativeExtend:
       case ABIArgInfo::Direct: {
         llvm::Type *RetIRTy = ConvertType(RetTy);
         if (RetAI.getCoerceToType() == RetIRTy &&
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 86f96b72170032..c2873605e9e008 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -70,6 +70,9 @@ LLVM_DUMP_METHOD void ABIArgInfo::dump() const {
     else
       OS << "null";
     break;
+  case ConservativeExtend:
+    OS << "ConservativeExtend";
+    break;
   }
   OS << ")\n";
 }
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index 5324c8d366b829..bf9e0d223d243d 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -993,9 +993,18 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State,
   bool InReg = shouldPrimitiveUseInReg(Ty, State);
 
   if (isPromotableIntegerTypeForABI(Ty)) {
-    if (InReg)
-      return ABIArgInfo::getExtendInReg(Ty, CGT.ConvertType(Ty));
-    return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));
+    switch (getCodeGenOpts().getExtendIntegerArgs()) {
+    case CodeGenOptions::ExtendIntegerArgsKind::Assumed:
+      return InReg ? ABIArgInfo::getExtendInReg(Ty, CGT.ConvertType(Ty))
+                   : ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));
+    case CodeGenOptions::ExtendIntegerArgsKind::Conservative:
+      return InReg
+                 ? ABIArgInfo::getConservativeExtendInReg(Ty, CGT.ConvertType(Ty))
+                 : ABIArgInfo::getConservativeExtend(Ty, CGT.ConvertType(Ty));
+    case CodeGenOptions::ExtendIntegerArgsKind::Direct:
+    // ExtendIntegerArgsKind::Direct will be handled at the last.
+      break;
+    }
   }
 
   if (const auto *EIT = Ty->getAs<BitIntType>()) {
@@ -1118,6 +1127,7 @@ static bool isArgInAlloca(const ABIArgInfo &Info) {
   case ABIArgInfo::Indirect:
   case ABIArgInfo::Direct:
   case ABIArgInfo::Extend:
+  case ABIArgInfo::ConservativeExtend:
     return !Info.getInReg();
   case ABIArgInfo::Expand:
   case ABIArgInfo::CoerceAndExpand:
@@ -2996,10 +3006,15 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs,
       // Treat an enum type as its underlying type.
       if (const auto *ED = Ty->getAsEnumDecl())
         Ty = ED->getIntegerType();
-
+      auto Kind = getCodeGenOpts().getExtendIntegerArgs();
       if (Ty->isIntegralOrEnumerationType() &&
-          isPromotableIntegerTypeForABI(Ty))
+          isPromotableIntegerTypeForABI(Ty)) {
+      // ExtendIntegerArgsKind::Direct will be handled at the last.
+      if (Kind == CodeGenOptions::ExtendIntegerArgsKind::Conservative)
+        return ABIArgInfo::getConservativeExtend(Ty, CGT.ConvertType(Ty));
+      else if (Kind == CodeGenOptions::ExtendIntegerArgsKind::Assumed)
         return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));
+      }
     }
 
     if (ResType->isIntegerTy(128)) {
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 0893b481f4ce64..c4a8525b25d6b2 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7461,6 +7461,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.addOptOutFlag(CmdArgs, options::OPT_mstack_arg_probe,
                      options::OPT_mno_stack_arg_probe);
 
+  // TODO: Support 'default' for OPT_mextend_small_integers_EQ
+  if (Args.getLastArgValue(options::OPT_mextend_small_integers_EQ) == "default")
+    D.Diag(diag::err_drv_unsupported_option_argument)
+        << "mextend-small-integers"
+        << "default";
+  Args.AddLastArg(CmdArgs, options::OPT_mextend_small_integers_EQ);
+
   if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
                                options::OPT_mno_restrict_it)) {
     if (A->getOption().matches(options::OPT_mrestrict_it)) {
diff --git a/clang/test/CodeGen/2007-06-18-SextAttrAggregate.c b/clang/test/CodeGen/2007-06-18-SextAttrAggregate.c
index ccfdc1a1c6cfa9..d0a830e84acfb2 100644
--- a/clang/test/CodeGen/2007-06-18-SextAttrAggregate.c
+++ b/clang/test/CodeGen/2007-06-18-SextAttrAggregate.c
@@ -1,12 +1,12 @@
 // RUN: %clang_cc1 -no-enable-noundef-analysis %s -o - -emit-llvm | FileCheck %s
-// XFAIL: target={{(aarch64|arm64).*}}, target=x86_64-pc-windows-msvc, target=x86_64-{{(pc|w64)}}-windows-gnu, target=x86_64-pc-windows-cygnus
+// XFAIL: target={{(aarch64|arm64).*}}, target=x86_64-pc-windows-msvc, target=x86_64-{{(pc|w64)}}-windows-gnu, target=x86_64-pc-windows-cygnus, target=x86_64-{{.*}}-linux{{.*}}
 
 // PR1513
 
 // AArch64 ABI actually requires the reverse of what this is testing: the callee
 // does any extensions and remaining bits are unspecified.
 
-// Win64 ABI does expect extensions for type smaller than 64bits.
+// X86_64 ABI does expect extensions for type smaller than 64bits.
 
 // Technically this test wasn't written to test that feature, but it's a
 // valuable check nevertheless.
diff --git a/clang/test/CodeGen/X86/integer_argument_passing.c b/clang/test/CodeGen/X86/integer_argument_passing.c
new file mode 100644
index 00000000000000..0c2c191978c9cf
--- /dev/null
+++ b/clang/test/CodeGen/X86/integer_argument_passing.c
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -O2 -triple -x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -triple -i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -triple -i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple -x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple -i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple -i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple -x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple -i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple -i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple -x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple -i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple -i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// TODO: enable the belowing tests when 'default' is supported.
+// %clang_cc1 -O2 -mextend-small-integers=default -triple -x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// %clang_cc1 -O2 -mextend-small-integers=default -triple -i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// %clang_cc1 -O2 -mextend-small-integers=default -triple -i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+
+
+// CALLEE-EXTEND: define{{.*}} i32 @ZeroExtend(i8 noundef %a, i16 noundef %b)
+// CALLEE-NO-EXTEND: define{{.*}} i32 @ZeroExtend(i8 noundef zeroext %a, i16 noundef zeroext %b)
+unsigned ZeroExtend(unsigned char a, unsigned short b) {
+  return a*b;
+}
+
+// CALLEE-EXTEND: define{{.*}} i32 @SignExtend(i8 noundef %a, i16 noundef %b)
+// CALLEE-NO-EXTEND: define{{.*}} i32 @SignExtend(i8 noundef signext %a, i16 noundef signext %b)
+int SignExtend(char a, short b) {
+  return a*b;
+}
+
+extern void f0(unsigned char x);
+extern void f1(unsigned short x);
+extern void f2(char x);
+extern void f3(short x);
+
+// CALLER-EXTEND: call void @f0(i8 noundef zeroext {{.*}})
+// CALLER-NO-EXTEND: call void @f0(i8 noundef {{.*}})
+void caller0(unsigned char x) { f0(x); }
+// CALLER-EXTEND: call void @f1(i16 noundef zeroext {{.*}})
+// CALLER-NO-EXTEND: call void @f1(i16 noundef {{.*}})
+void caller1(unsigned short x) { f1(x); }
+// CALLER-EXTEND: call void @f2(i8 noundef signext {{.*}})
+// CALLER-NO-EXTEND: call void @f2(i8 noundef {{.*}})
+void caller2(char x) { f2(x); }
+// CALLER-EXTEND: call void @f3(i16 noundef signext {{.*}})
+// CALLER-NO-EXTEND: call void @f3(i16 noundef {{.*}})
+void caller3(short x) { f3(x); }
diff --git a/clang/test/CodeGen/X86/x86_32-arguments-darwin.c b/clang/test/CodeGen/X86/x86_32-arguments-darwin.c
index 8eeba631157d07..a44981769b28e8 100644
--- a/clang/test/CodeGen/X86/x86_32-arguments-darwin.c
+++ b/clang/test/CodeGen/X86/x86_32-arguments-darwin.c
@@ -30,7 +30,7 @@ long double f5(void) {
   return 0;
 }
 
-// CHECK-LABEL: define{{.*}} void @f6(i8 noundef signext %a0, i16 noundef signext %a1, i32 noundef %a2, i64 noundef %a3, ptr noundef %a4)
+// CHECK-LABEL: define{{.*}} void @f6(i8 noundef %a0, i16 noundef %a1, i32 noundef %a2, i64 noundef %a3, ptr noundef %a4)
 void f6(char a0, short a1, int a2, long long a3, void *a4) {}
 
 // CHECK-LABEL: define{{.*}} void @f7(i32 noundef %a0)
@@ -226,7 +226,7 @@ typedef int v4i32 __attribute__((__vector_size__(16)));
 v4i32 f55(v4i32 arg) { return arg+arg; }
 
 // CHECK-LABEL: define{{.*}} void @f56(
-// CHECK: i8 noundef signext %a0, ptr noundef byval(%struct.s56_0) align 4 %a1,
+// CHECK: i8 noundef %a0, ptr noundef byval(%struct.s56_0) align 4 %a1,
 // CHECK: i64 noundef %a2.coerce, ptr noundef byval(%struct.s56_1) align 4 %0,
 // CHECK: i64 noundef %a4.coerce, ptr noundef byval(%struct.s56_2) align 4 %1,
 // CHECK: <4 x i32> noundef %a6, ptr noundef byval(%struct.s56_3) align 16 %a7,
diff --git a/clang/test/CodeGen/X86/x86_32-arguments-linux.c b/clang/test/CodeGen/X86/x86_32-arguments-linux.c
index 6da292b6b7009a..248a2347723071 100644
--- a/clang/test/CodeGen/X86/x86_32-arguments-linux.c
+++ b/clang/test/CodeGen/X86/x86_32-arguments-linux.c
@@ -2,7 +2,7 @@
 // RUN: FileCheck < %t %s
 
 // CHECK-LABEL: define{{.*}} void @f56(
-// CHECK: i8 noundef signext %a0, ptr noundef byval(%struct.s56_0) align 4 %a1,
+// CHECK: i8 noundef %a0, ptr noundef byval(%struct.s56_0) align 4 %a1,
 // CHECK: i64 noundef %a2.coerce, ptr noundef byval(%struct.s56_1) align 4 %0,
 // CHECK: <1 x double> noundef %a4, ptr noundef byval(%struct.s56_2) align 4 %1,
 // CHECK: <4 x i32> noundef %a6, ptr noundef byval(%struct.s56_3) align 4 %2,
diff --git a/clang/test/CodeGen/X86/x86_64-arguments.c b/clang/test/CodeGen/X86/x86_64-arguments.c
index 73f99b9a814b4e..6c5e0d6d87b709 100644
--- a/clang/test/CodeGen/X86/x86_64-arguments.c
+++ b/clang/test/CodeGen/X86/x86_64-arguments.c
@@ -36,7 +36,7 @@ long double f5(void) {
   return 0;
 }
 
-// CHECK-LABEL: define{{.*}} void @f6(i8 noundef signext %a0, i16 noundef signext %a1, i32 noundef %a2, i64 noundef %a3, ptr noundef %a4)
+// CHECK-LABEL: define{{.*}} void @f6(i8 noundef %a0, i16 noundef %a1, i32 noundef %a2, i64 noundef %a3, ptr noundef %a4)
 void f6(char a0, short a1, int a2, long long a3, void *a4) {
 }
 
diff --git a/clang/test/CodeGen/attr-noundef.cpp b/clang/test/CodeGen/attr-noundef.cpp
index 9b14381d004b84..6a360c248b4f46 100644
--- a/clang/test/CodeGen/attr-noundef.cpp
+++ b/clang/test/CodeGen/attr-noundef.cpp
@@ -160,7 +160,7 @@ void pass_large_BitInt(_BitInt(127) e) {
 
 // CHECK-INTEL: [[DEF]] noundef i3 @{{.*}}ret_BitInt{{.*}}()
 // CHECK-AARCH: [[DEF]] noundef i3 @{{.*}}ret_BitInt{{.*}}()
-// CHECK-INTEL: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 noundef signext %
+// CHECK-INTEL: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 noundef %
 // CHECK-AARCH: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 noundef %
 // CHECK-INTEL: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i64 noundef %{{.*}}, i64 noundef %
 // CHECK-AARCH: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i127 noundef %
diff --git a/clang/test/CodeGen/builtin-align.c b/clang/test/CodeGen/builtin-align.c
index 932b93972a85e6..2743bd5234bcd6 100644
--- a/clang/test/CodeGen/builtin-align.c
+++ b/clang/test/CodeGen/builtin-align.c
@@ -98,7 +98,7 @@ TYPE get_type(void) {
 // CHECK-LONG-NEXT:    ret i1 [[IS_ALIGNED]]
 //
 // CHECK-USHORT-LABEL: define {{[^@]+}}@is_aligned
-// CHECK-USHORT-SAME: (i16 noundef zeroext [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
+// CHECK-USHORT-SAME: (i16 noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
 // CHECK-USHORT-NEXT:  entry:
 // CHECK-USHORT-NEXT:    [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN:%.*]] to i16
 // CHECK-USHORT-NEXT:    [[MASK:%.*]] = sub i16 [[ALIGNMENT]], 1
@@ -142,7 +142,7 @@ _Bool is_aligned(TYPE ptr, unsigned align) {
 // CHECK-LONG-NEXT:    ret i64 [[ALIGNED_RESULT]]
 //
 // CHECK-USHORT-LABEL: define {{[^@]+}}@align_up
-// CHECK-USHORT-SAME: (i16 noundef zeroext [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
+// CHECK-USHORT-SAME: (i16 noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
 // CHECK-USHORT-NEXT:  entry:
 // CHECK-USHORT-NEXT:    [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN:%.*]] to i16
 // CHECK-USHORT-NEXT:    [[MASK:%.*]] = sub i16 [[ALIGNMENT]], 1
@@ -184,7 +184,7 @@ TYPE align_up(TYPE ptr, unsigned align) {
 // CHECK-LONG-NEXT:    ret i64 [[ALIGNED_RESULT]]
 //
 // CHECK-USHORT-LABEL: define {{[^@]+}}@align_down
-// CHECK-USHORT-SAME: (i16 noundef zeroext [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
+// CHECK-USHORT-SAME: (i16 noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
 // CHECK-USHORT-NEXT:  entry:
 // CHECK-USHORT-NEXT:    [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN:%.*]] to i16
 // CHECK-USHORT-NEXT:    [[MASK:%.*]] = sub i16 [[ALIGNMENT]], 1
diff --git a/clang/test/CodeGen/builtins-memset-inline.c b/clang/test/CodeGen/builtins-memset-inline.c
index ea429024f187cd..3af42cd8d5e1f3 100644
--- a/clang/test/CodeGen/builtins-memset-inline.c
+++ b/clang/test/CodeGen/builtins-memset-inline.c
@@ -2,19 +2,19 @@
 // REQUIRES: x86-registered-target
 // RUN: %clang_cc1 -triple x86_64-unknown-linux -emit-llvm %s -o - | FileCheck %s
 
-// CHECK-LABEL: define{{.*}} void @test_memset_inline_0(ptr noundef %dst, i8 noundef signext %value)
+// CHECK-LABEL: define{{.*}} void @test_memset_inline_0(ptr noundef %dst, i8 noundef %value)
 void test_memset_inline_0(void *dst, char value) {
   // CHECK:    call void @llvm.memset.inline.p0.i64(ptr align 1 %0, i8 %2, i64 0, i1 false)
   __builtin_memset_inline(dst, value, 0);
 }
 
-// CHECK-LABEL: define{{.*}} void @test_memset_inline_1(ptr noundef %dst, i8 noundef signext %value)
+// CHECK-LABEL: define{{.*}} void @test_memset_inline_1(ptr noundef %dst, i8 noundef %value)
 void test_memset_inline_1(void *dst, char value) {
   // CHECK:    call void @llvm.memset.inline.p0.i64(ptr align 1 %0, i8 %2, i64 1, i1 false)
   __builtin_memset_inline(dst, value, 1);
 }
 
-// CHECK-LABEL: define{{.*}} void @test_memset_inline_4(ptr noundef %dst, i8 noundef signext %value)
+// CHECK-LABEL: define{{.*}} void @test_memset_inline_4(ptr noundef %dst, i8 noundef %value)
 void test_memset_inline_4(void *dst, char value) {
   // CHECK:    call void @llvm.memset.inline.p0.i64(ptr align 1 %0, i8 %2, i64 4, i1 false)
   __builtin_memset_inline(dst, value, 4);
diff --git a/clang/test/CodeGen/catch-implicit-integer-sign-changes.c b/clang/test/CodeGen/catch-implicit-integer-sign-changes.c
index 8d5bad73112e07..e7ca650dbcb79f 100644
--- a/clang/test/CodeGen/catch-implicit-integer-sign-changes.c
+++ b/clang/test/CodeGen/catch-implicit-integer-sign-changes.c
@@ -99,7 +99,7 @@ unsigned char signed_int_to_unsigned_char(signed int src) {
 // These 3 result (after optimizations) in simple 'icmp sge i8 %src, 0'
 
 // CHECK-LABEL: @signed_char_to_unsigned_char
-// CHECK-SAME: (i8 noundef signext %[[SRC:.*]])
+// CHECK-SAME: (i8 noundef %[[SRC:.*]])
 unsigned char signed_char_to_unsigned_char(signed char src) {
   // CHECK: %[[SRC_ADDR:.*]] = alloca i8
   // CHECK-NEXT: store i8 %[[SRC]], ptr %[[SRC_ADDR]]
@@ -122,7 +122,7 @@ unsigned char signed_char_to_unsigned_char(signed char src) {
 }
 
 // CHECK-LABEL: @unsigned_char_to_signed_char
-// CHECK-SAME: (i8 noundef zeroext %[[SRC:.*]])
+// CHECK-SAME: (i8 noundef %[[SRC:.*]])
 signed char unsigned_char_to_signed_char(unsigned char src) {
   // CHECK: %[[SRC_ADDR:.*]] = alloca i8
   // CHECK-NEXT: store i8 %[[SRC]], ptr %[[SRC_ADDR]]
@@ -145,7 +145,7 @@ signed char unsigned_char_to_signed_char(unsigned char src) {
 }
 
 // CHECK-LABEL: @signed_char_to_unsigned_int
-// CHECK-SAME: (i8 noundef signext %[[SRC:.*]])
+// CHECK-SAME: (i8 noundef %[[SRC:.*]])
 unsigned int signed_char_to_unsigned_int(signed char src) {
   // CHECK: %[[SRC_ADDR:.*]] = alloca i8
   // CHECK-NEXT: store i8 %[[SRC]], ptr %[[SRC_ADDR]]
diff --git a/clang/test/CodeGen/ext-int-cc.c b/clang/test/CodeGen/ext-int-cc.c
index 3cc5dd94a2e0c4..09e9279fa7cc05 100644
--- a/clang/test/CodeGen/ext-int-cc.c
+++ b/clang/test/CodeGen/ext-int-cc.c
@@ -93,10 +93,10 @@ void ParamPassing2(_BitInt(127) b, _BitInt(63) c) {}
 
 // Make sure we follow the signext rules for promotable integer types.
 void ParamPassing3(_BitInt(15) a, _BitInt(31) b) {}
-// LIN64: define{{.*}} void @ParamPassing3(i15 signext %{{.+}}, i31 signext %{{.+}})
+// LIN64: define{{.*}} void @ParamPassing3(i15 %{{.+}}, i31 %{{.+}})
 // WIN64: define dso_local void @ParamPassing3(i15 %{{.+}}, i31 %{{.+}})
-// LIN32: define{{.*}} void @ParamPassing3(i15 signext %{{.+}}, i31 signext %{{.+}})
-// WIN32: define dso_local void @ParamPassing3(i15 signext %{{.+}}, i31 signext %{{.+}})
+// LIN32: define{{.*}} void @ParamPassing3(i15 %{{.+}}, i31 %{{.+}})
+// WIN32: define dso_local void @ParamPassing3(i15 %{{.+}}, i31 %{{.+}})
 // NVPTX64: define{{.*}} void @ParamPassing3(i15 signext %{{.+}}, i31 signext %{{.+}})
 // NVPTX: define{{.*}} void @ParamPassing3(i15 signext %{{.+}}, i31 signext %{{.+}})
 // SPARCV9: define{{.*}} void @ParamPassing3(i15 signext %{{.+}}, i31 signext %{{.+}})
diff --git a/clang/test/CodeGen/function-attributes.c b/clang/test/CodeGen/function-attributes.c
index b55cdb1606e441..c0071ebf3a5bb5 100644
--- a/clang/test/CodeGen/function-attributes.c
+++ b/clang/test/CodeGen/function-attributes.c
@@ -3,12 +3,12 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -disable-llvm-passes -Os -std=c99 -o - %s | FileCheck %s
 // CHECK: define{{.*}} i8 @f0(i32 noundef %x) [[NUW:#[0-9]+]]
 // CHECK: define{{.*}} i8 @f1(i32 noundef %x) [[NUW]]
-// CHECK: define{{.*}} void @f2(i8 noundef signext %x) [[NUW]]
-// CHECK: define{{.*}} void @f3(i8 noundef zeroext %x) [[NUW]]
+// CHECK: define{{.*}} void @f2(i8 noundef %x) [[NUW]]
+// CHECK: define{{.*}} void @f3(i8 noundef %x) [[NUW]]
 // CHECK: define{{.*}} i16 @f4(i32 noundef %x) [[NUW]]
 // CHECK: define{{.*}} i16 @f5(i32 noundef %x) [[NUW]]
-// CHECK: define{{.*}} void @f6(i16 noundef signext %x) [[NUW]]
-// CHECK: define{{.*}} void @f7(i16 noundef zeroext %x) [[NUW]]
+// CHECK: define{{.*}} void @f6(i16 noundef %x) [[NUW]]
+// CHECK: define{{.*}} void @f7(i16 noundef %x) [[NUW]]
 
 signed char f0(int x) { return x; }
 
diff --git a/clang/test/CodeGen/mangle-windows.c b/clang/test/CodeGen/mangle-windows.c
index e1b06e72a96350..8ffcdf11833277 100644
--- a/clang/test/CodeGen/mangle-windows.c
+++ b/clang/test/CodeGen/mangle-windows.c
@@ -49,7 +49,7 @@ void __fastcall f8(long long a) {}
 // X64: define dso_local void @f8(
 
 void __fastcall f9(long long a, char b, char c, short d) {}
-// CHECK: define dso_local x86_fastcallcc void @"\01 at f9@20"(i64 noundef %a, i8 inreg noundef signext %b, i8 inreg noundef signext %c, i16 noundef signext %d)
+// CHECK: define dso_local x86_fastcallcc void @"\01 at f9@20"(i64 noundef %a, i8 inreg noundef %b, i8 inreg noundef %c, i16 noundef %d)
 // X64: define dso_local void @f9(
 
 void f12(void) {}
diff --git a/clang/test/CodeGen/matrix-type-builtins.c b/clang/test/CodeGen/matrix-type-builtins.c
index f6e67d5933ee4f..5517c8bdc3276a 100644
--- a/clang/test/CodeGen/matrix-type-builtins.c
+++ b/clang/test/CodeGen/matrix-type-builtins.c
@@ -154,7 +154,7 @@ void column_major_load_with_stride_math_int(int *Ptr, int S) {
 }
 
 void column_major_load_with_stride_math_s_int(int *Ptr, short S) {
-  // COMMON-LABEL:  define{{.*}} void @column_major_load_with_stride_math_s_int(ptr %Ptr, i16 signext %S)
+  // COMMON-LABEL:  define{{.*}} void @column_major_load_with_stride_math_s_int(ptr %Ptr, i16 %S)
   // COMMON:         [[S:%.*]] = load i16, ptr %S.addr, align 2
   // COMMON-NEXT:    [[S_EXT:%.*]] = sext i16 [[S]] to i32
   // COMMON-NEXT:    [[STRIDE:%.*]] = add nsw i32 [[S_EXT]], 32
@@ -261,7 +261,7 @@ void column_major_store_with_stride_math_int(int *Ptr, int S) {
 }
 
 void column_major_store_with_stride_math_s_int(int *Ptr, short S) {
-  // COMMON-LABEL: define{{.*}} void @column_major_store_with_stride_math_s_int(ptr %Ptr, i16 signext %S)
+  // COMMON-LABEL: define{{.*}} void @column_major_store_with_stride_math_s_int(ptr %Ptr, i16 %S)
   // COMMON:         [[M:%.*]] = load <80 x i32>, ptr {{.*}}, align 4
   // CHECK32-NEXT:   [[PTR:%.*]] = load ptr, ptr %Ptr.addr, align 4
   // CHECK64-NEXT:   [[PTR:%.*]] = load ptr, ptr %Ptr.addr, align 8
diff --git a/clang/test/CodeGen/matrix-type-operators.c b/clang/test/CodeGen/matrix-type-operators.c
index dde9857921cd12..8cef8cf75c115c 100644
--- a/clang/test/CodeGen/matrix-type-operators.c
+++ b/clang/test/CodeGen/matrix-type-operators.c
@@ -321,7 +321,7 @@ void subtract_compound_matrix_matrix_unsigned_long_long(ullx4x2_t a, ullx4x2_t b
 }
 
 void add_matrix_scalar_int_short(ix9x3_t a, short vs) {
-  // CHECK-LABEL: define{{.*}} void @add_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef signext %vs)
+  // CHECK-LABEL: define{{.*}} void @add_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef %vs)
   // NOOPT:        [[MATRIX:%.*]] = load <27 x i32>, ptr [[MAT_ADDR:%.*]], align 4{{$}}
   // NOOPT-NEXT:   [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:          [[MATRIX:%.*]] = load <27 x i32>, ptr [[MAT_ADDR:%.*]], align 4, !tbaa !{{[0-9]+}}{{$}}
@@ -336,7 +336,7 @@ void add_matrix_scalar_int_short(ix9x3_t a, short vs) {
 }
 
 void add_compound_matrix_scalar_int_short(ix9x3_t a, short vs) {
-  // CHECK-LABEL: define{{.*}} void @add_compound_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef signext %vs)
+  // CHECK-LABEL: define{{.*}} void @add_compound_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef %vs)
   // NOOPT:       [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:         [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2, !tbaa !{{[0-9]+}}{{$}}
   // CHECK-NEXT:  [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i32
@@ -351,7 +351,7 @@ void add_compound_matrix_scalar_int_short(ix9x3_t a, short vs) {
 }
 
 void subtract_compound_matrix_scalar_int_short(ix9x3_t a, short vs) {
-  // CHECK-LABEL: define{{.*}} void @subtract_compound_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef signext %vs)
+  // CHECK-LABEL: define{{.*}} void @subtract_compound_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef %vs)
   // NOOPT:       [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:         [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2, !tbaa !{{[0-9]+}}{{$}}
   // CHECK-NEXT:  [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i32
@@ -456,7 +456,7 @@ void subtract_compound_matrix_scalar_int_unsigned_long_long(ix9x3_t a, unsigned
 }
 
 void add_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
-  // CHECK-LABEL: define{{.*}} void @add_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef signext %vs)
+  // CHECK-LABEL: define{{.*}} void @add_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef %vs)
   // NOOPT:         [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:           [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2, !tbaa !{{[0-9]+}}{{$}}
   // CHECK-NEXT:    [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i64
@@ -471,7 +471,7 @@ void add_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
 }
 
 void add_compound_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
-  // CHECK-LABEL: define{{.*}} void @add_compound_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef signext %vs)
+  // CHECK-LABEL: define{{.*}} void @add_compound_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef %vs)
   // NOOPT:       [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:         [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2, !tbaa !{{[0-9]+}}{{$}}
   // CHECK-NEXT:  [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i64
@@ -486,7 +486,7 @@ void add_compound_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
 }
 
 void subtract_compound_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
-  // CHECK-LABEL: define{{.*}} void @subtract_compound_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef signext %vs)
+  // CHECK-LABEL: define{{.*}} void @subtract_compound_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef %vs)
   // NOOPT:       [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:         [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2, !tbaa !{{[0-9]+}}{{$}}
   // CHECK-NEXT:  [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i64
diff --git a/clang/test/CodeGen/ms-inline-asm.c b/clang/test/CodeGen/ms-inline-asm.c
index c3eef9a23e1661..714167b724590e 100644
--- a/clang/test/CodeGen/ms-inline-asm.c
+++ b/clang/test/CodeGen/ms-inline-asm.c
@@ -581,7 +581,7 @@ void t40(float a) {
 }
 
 void t41(unsigned short a) {
-// CHECK-LABEL: define{{.*}} void @t41(i16 noundef zeroext %a)
+// CHECK-LABEL: define{{.*}} void @t41(i16 noundef %a)
   __asm mov cs, a;
 // CHECK: mov cs, $0
   __asm mov ds, a;
diff --git a/clang/test/CodeGen/regcall.c b/clang/test/CodeGen/regcall.c
index c432e085bdc034..c4985044a6edd2 100644
--- a/clang/test/CodeGen/regcall.c
+++ b/clang/test/CodeGen/regcall.c
@@ -14,9 +14,9 @@ void __attribute__((regcall)) v1b(int a, int b) {}
 // X64: define dso_local x86_regcallcc void @__regcall3__v1b(i32 noundef %a, i32 noundef %b)
 
 void __regcall v2(char a, char b) {}
-// X86: define dso_local x86_regcallcc void @__regcall3__v2(i8 inreg noundef signext %a, i8 inreg noundef signext %b)
+// X86: define dso_local x86_regcallcc void @__regcall3__v2(i8 inreg noundef %a, i8 inreg noundef %b)
 // Win64: define dso_local x86_regcallcc void @__regcall3__v2(i8 noundef %a, i8 noundef %b)
-// Lin64: define dso_local x86_regcallcc void @__regcall3__v2(i8 noundef signext %a, i8 noundef signext %b)
+// Lin64: define dso_local x86_regcallcc void @__regcall3__v2(i8 noundef %a, i8 noundef %b)
 
 struct Small { int x; };
 void __regcall v3(int a, struct Small b, int c) {}
diff --git a/clang/test/CodeGen/vectorcall.c b/clang/test/CodeGen/vectorcall.c
index 5b2c9bad07ba79..791b0eb0083d31 100644
--- a/clang/test/CodeGen/vectorcall.c
+++ b/clang/test/CodeGen/vectorcall.c
@@ -6,7 +6,7 @@ void __vectorcall v1(int a, int b) {}
 // X64: define dso_local x86_vectorcallcc void @"\01v1@@16"(i32 noundef %a, i32 noundef %b)
 
 void __vectorcall v2(char a, char b) {}
-// X86: define dso_local x86_vectorcallcc void @"\01v2@@8"(i8 inreg noundef signext %a, i8 inreg noundef signext %b)
+// X86: define dso_local x86_vectorcallcc void @"\01v2@@8"(i8 inreg noundef %a, i8 inreg noundef %b)
 // X64: define dso_local x86_vectorcallcc void @"\01v2@@16"(i8 noundef %a, i8 noundef %b)
 
 struct Small { int x; };
diff --git a/clang/test/CodeGenCXX/exceptions.cpp b/clang/test/CodeGenCXX/exceptions.cpp
index 6c920d71867095..8fbb056e746540 100644
--- a/clang/test/CodeGenCXX/exceptions.cpp
+++ b/clang/test/CodeGenCXX/exceptions.cpp
@@ -216,7 +216,7 @@ namespace test3 {
 
   A *b(bool cond) {
 
-    // CHECK:    define{{( dso_local)?}} ptr @_ZN5test31bEb(i1 zeroext
+    // CHECK:    define{{( dso_local)?}} ptr @_ZN5test31bEb(i1
     // CHECK:      [[SAVED0:%.*]] = alloca ptr
     // CHECK-NEXT: [[SAVED1:%.*]] = alloca ptr
     // CHECK-NEXT: [[CLEANUPACTIVE:%.*]] = alloca i1
diff --git a/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp b/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
index a60781c164785c..48c7b5f5c41a3d 100644
--- a/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
+++ b/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
@@ -94,7 +94,7 @@ int HasConditionalCleanup(bool cond) {
   return (cond ? TakesTwo(A(), A()) : CouldThrow());
 }
 
-// WIN32-LABEL: define dso_local noundef i32 @"?HasConditionalCleanup@@YAH_N at Z"(i1 noundef zeroext %{{.*}}) {{.*}} {
+// WIN32-LABEL: define dso_local noundef i32 @"?HasConditionalCleanup@@YAH_N at Z"(i1 noundef %{{.*}}) {{.*}} {
 // WIN32:   store i1 false
 // WIN32:   br i1
 // WIN32:   call ptr @llvm.stacksave.p0()
diff --git a/clang/test/CodeGenCXX/new-overflow.cpp b/clang/test/CodeGenCXX/new-overflow.cpp
index 8a193955574e1e..31c9cc73e88953 100644
--- a/clang/test/CodeGenCXX/new-overflow.cpp
+++ b/clang/test/CodeGenCXX/new-overflow.cpp
@@ -9,7 +9,7 @@ namespace test0 {
 
   typedef A elt;
 
-  // CHECK:    define{{.*}} ptr @_ZN5test04testEs(i16 noundef signext
+  // CHECK:    define{{.*}} ptr @_ZN5test04testEs(i16 noundef
   // CHECK:      [[N:%.*]] = sext i16 {{%.*}} to i32
   // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 4)
   // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1
@@ -31,7 +31,7 @@ namespace test1 {
 
   typedef A elt[100];
 
-  // CHECK:    define{{.*}} ptr @_ZN5test14testEs(i16 noundef signext
+  // CHECK:    define{{.*}} ptr @_ZN5test14testEs(i16 noundef
   // CHECK:      [[N:%.*]] = sext i16 {{%.*}} to i32
   // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400)
   // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1
@@ -55,7 +55,7 @@ namespace test2 {
 
   typedef A elt[100];
 
-  // CHECK:    define{{.*}} ptr @_ZN5test24testEs(i16 noundef signext
+  // CHECK:    define{{.*}} ptr @_ZN5test24testEs(i16 noundef
   // CHECK:      [[N:%.*]] = sext i16 {{%.*}} to i32
   // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400)
   // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1
@@ -81,7 +81,7 @@ namespace test4 {
 
   typedef A elt;
 
-  // CHECK:    define{{.*}} ptr @_ZN5test44testEs(i16 noundef signext
+  // CHECK:    define{{.*}} ptr @_ZN5test44testEs(i16 noundef
   // CHECK:      [[N:%.*]] = sext i16 {{%.*}} to i32
   // CHECK-NEXT: call noalias noundef nonnull ptr @_Znaj(i32 noundef [[N]])
   // CHECK:      getelementptr inbounds {{.*}}, i32 [[N]]
@@ -116,7 +116,7 @@ namespace test6 {
 
   typedef A elt;
 
-  // CHECK:    define{{.*}} ptr @_ZN5test64testEt(i16 noundef zeroext
+  // CHECK:    define{{.*}} ptr @_ZN5test64testEt(i16 noundef
   // CHECK:      [[N:%.*]] = zext i16 {{%.*}} to i32
   // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 4)
   // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1
@@ -138,7 +138,7 @@ namespace test7 {
 
   typedef A elt[100];
 
-  // CHECK:    define{{.*}} ptr @_ZN5test74testEt(i16 noundef zeroext
+  // CHECK:    define{{.*}} ptr @_ZN5test74testEt(i16 noundef
   // CHECK:      [[N:%.*]] = zext i16 {{%.*}} to i32
   // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400)
   // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1
diff --git a/clang/test/CodeGenCXX/virtual-bases.cpp b/clang/test/CodeGenCXX/virtual-bases.cpp
index 325e67b4e72882..fcb6a360091537 100644
--- a/clang/test/CodeGenCXX/virtual-bases.cpp
+++ b/clang/test/CodeGenCXX/virtual-bases.cpp
@@ -20,8 +20,8 @@ struct C : virtual A {
   C(bool);
 };
 
-// CHECK-LABEL: define{{.*}} void @_ZN1CC2Eb(ptr {{[^,]*}} %this, ptr noundef %vtt, i1 noundef zeroext %0) unnamed_addr
-// CHECK-LABEL: define{{.*}} void @_ZN1CC1Eb(ptr {{[^,]*}} %this, i1 noundef zeroext %0) unnamed_addr
+// CHECK-LABEL: define{{.*}} void @_ZN1CC2Eb(ptr {{[^,]*}} %this, ptr noundef %vtt, i1 noundef %0) unnamed_addr
+// CHECK-LABEL: define{{.*}} void @_ZN1CC1Eb(ptr {{[^,]*}} %this, i1 noundef %0) unnamed_addr
 C::C(bool) { }
 
 // PR6251
diff --git a/clang/test/CodeGenObjC/property-atomic-bool.m b/clang/test/CodeGenObjC/property-atomic-bool.m
index aac5295999b254..1afefab0a89adf 100644
--- a/clang/test/CodeGenObjC/property-atomic-bool.m
+++ b/clang/test/CodeGenObjC/property-atomic-bool.m
@@ -5,7 +5,7 @@
 // CHECK:   %[[TOBOOL:.*]] = icmp ne i8 %[[ATOMIC_LOAD]], 0
 // CHECK:   ret i1 %[[TOBOOL]]
 
-// CHECK-LABEL: define internal void @"\01-[A0 setP:]"({{.*}} i1 noundef zeroext {{.*}})
+// CHECK-LABEL: define internal void @"\01-[A0 setP:]"({{.*}} i1 noundef {{.*}})
 // CHECK:   store atomic i8 %{{.*}}, ptr %{{.*}} seq_cst, align 1
 // CHECK:   ret void
 
@@ -14,7 +14,7 @@
 // CHECK:   %[[TOBOOL:.*]] = icmp ne i8 %[[ATOMIC_LOAD]], 0
 // CHECK:   ret i1 %[[TOBOOL]]
 
-// CHECK-LABEL: define internal void @"\01-[A1 setP:]"({{.*}} i1 noundef zeroext %p)
+// CHECK-LABEL: define internal void @"\01-[A1 setP:]"({{.*}} i1 noundef %p)
 // CHECK:   store atomic i8 %{{.*}}, ptr %{{.*}} unordered, align 1
 // CHECK:   ret void
 
diff --git a/clang/test/OpenMP/target_codegen_global_capture.cpp b/clang/test/OpenMP/target_codegen_global_capture.cpp
index dd47b73d405fa8..410dccae97d29e 100644
--- a/clang/test/OpenMP/target_codegen_global_capture.cpp
+++ b/clang/test/OpenMP/target_codegen_global_capture.cpp
@@ -1099,7 +1099,7 @@ int tbar2(short a, short b, short c, short d){
 //
 //
 // CHECK3-LABEL: define {{[^@]+}}@_Z3foossss
-// CHECK3-SAME: (i16 noundef signext [[A:%.*]], i16 noundef signext [[B:%.*]], i16 noundef signext [[C:%.*]], i16 noundef signext [[D:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK3-SAME: (i16 noundef [[A:%.*]], i16 noundef [[B:%.*]], i16 noundef [[C:%.*]], i16 noundef [[D:%.*]]) #[[ATTR0:[0-9]+]] {
 // CHECK3-NEXT:  entry:
 // CHECK3-NEXT:    [[A_ADDR:%.*]] = alloca i16, align 2
 // CHECK3-NEXT:    [[B_ADDR:%.*]] = alloca i16, align 2
@@ -1388,7 +1388,7 @@ int tbar2(short a, short b, short c, short d){
 //
 //
 // CHECK3-LABEL: define {{[^@]+}}@_Z3barssss
-// CHECK3-SAME: (i16 noundef signext [[A:%.*]], i16 noundef signext [[B:%.*]], i16 noundef signext [[C:%.*]], i16 noundef signext [[D:%.*]]) #[[ATTR0]] {
+// CHECK3-SAME: (i16 noundef [[A:%.*]], i16 noundef [[B:%.*]], i16 noundef [[C:%.*]], i16 noundef [[D:%.*]]) #[[ATTR0]] {
 // CHECK3-NEXT:  entry:
 // CHECK3-NEXT:    [[A_ADDR:%.*]] = alloca i16, align 2
 // CHECK3-NEXT:    [[B_ADDR:%.*]] = alloca i16, align 2
@@ -1700,7 +1700,7 @@ int tbar2(short a, short b, short c, short d){
 //
 //
 // CHECK3-LABEL: define {{[^@]+}}@_Z5tbar2ssss
-// CHECK3-SAME: (i16 noundef signext [[A:%.*]], i16 noundef signext [[B:%.*]], i16 noundef signext [[C:%.*]], i16 noundef signext [[D:%.*]]) #[[ATTR0]] {
+// CHECK3-SAME: (i16 noundef [[A:%.*]], i16 noundef [[B:%.*]], i16 noundef [[C:%.*]], i16 noundef [[D:%.*]]) #[[ATTR0]] {
 // CHECK3-NEXT:  entry:
 // CHECK3-NEXT:    [[A_ADDR:%.*]] = alloca i16, align 2
 // CHECK3-NEXT:    [[B_ADDR:%.*]] = alloca i16, align 2
@@ -1719,7 +1719,7 @@ int tbar2(short a, short b, short c, short d){
 //
 //
 // CHECK3-LABEL: define {{[^@]+}}@_Z4tbarIsEiT_S0_S0_S0_
-// CHECK3-SAME: (i16 noundef signext [[A:%.*]], i16 noundef signext [[B:%.*]], i16 noundef signext [[C:%.*]], i16 noundef signext [[D:%.*]]) #[[ATTR0]] comdat {
+// CHECK3-SAME: (i16 noundef [[A:%.*]], i16 noundef [[B:%.*]], i16 noundef [[C:%.*]], i16 noundef [[D:%.*]]) #[[ATTR0]] comdat {
 // CHECK3-NEXT:  entry:
 // CHECK3-NEXT:    [[A_ADDR:%.*]] = alloca i16, align 2
 // CHECK3-NEXT:    [[B_ADDR:%.*]] = alloca i16, align 2

>From 64e742da5593579abd8a1720e45881fc9e1d7c1a Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Sun, 25 Oct 2026 08:48:28 +0000
Subject: [PATCH 02/11] [Clang][ABI] Adapt -mextend-small-integers to the
 current codebase

Follow-up to the rebase of D124435, implementing the changes required by
the evolution of the codebase since 2022:

* Build fixes: ENUM_CODEGENOPT now takes a compatibility kind, options
  use Visibility<> instead of Flags<[CC1Option]>, and
  err_drv_unsupported_option_argument expects the option spelling.
  Handle the Default kind in the X86-32 switch to fix -Wswitch.
* ABIArgInfo now tracks zero extension separately from sign extension
  (to support NoExt), so make getConservativeExtend() set ZeroExt and
  allow isZeroExt()/setZeroExt()/isNoExt() on ConservativeExtend.
* Treat ConservativeExtend like Extend for noundef determination.
* clang/docs/ClangCommandLineReference.rst is now generated, so move
  the option documentation into a DocBrief in Options.td.
* Add ConservativeExtend support to the experimental LLVM ABI library:
  a new ArgInfo::ConservativeExtend kind and an ExtendIntegerArgs mode
  in X86ABICompatInfo (defaulting to Assumed, the previous behavior),
  which Clang initializes from -mextend-small-integers when using
  -fexperimental-abi-lowering. Also add it to the debug consistency
  check against the classic ABI implementation.
* CIR call-conv lowering uses the ABI library as well. Teach it to only
  put the extension attribute on call sites for conservative
  extensions, and default to conservative extension to match classic
  CodeGen. Plumbing the option itself through CIR is left as a
  MissingFeature.
* Update additional tests that started checking signext/zeroext on
  x86 parameters since the patch was written, add
  -fexperimental-abi-lowering RUN lines and fix the bogus "-triple
  -x86_64-..." spelling in the new test.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply at anthropic.com>
---
 clang/include/clang/Basic/CodeGenOptions.def  |  2 +-
 clang/include/clang/CIR/MissingFeatures.h     |  1 +
 clang/include/clang/CodeGen/CGFunctionInfo.h  | 13 +++--
 clang/include/clang/Options/Options.td        | 32 ++++++++++-
 .../Transforms/CallConvLoweringPass.cpp       | 11 ++--
 .../TargetLowering/CIRABIRewriteContext.cpp   | 31 ++++++-----
 clang/lib/CIR/Lowering/CIRPasses.cpp          |  5 ++
 clang/lib/CodeGen/CGCall.cpp                  | 19 ++++++-
 clang/lib/CodeGen/CodeGenModule.cpp           | 20 +++++--
 clang/lib/CodeGen/Targets/X86.cpp             |  3 +-
 clang/lib/Driver/ToolChains/Clang.cpp         | 12 +++--
 clang/test/CIR/CodeGen/attr-noundef.cpp       |  2 +-
 .../call-conv-lowering-x86_64-packed.c        |  4 +-
 .../call-conv-lowering-x86_64-variadic.c      |  4 +-
 .../CIR/CodeGen/call-conv-lowering-x86_64.c   | 25 ++++++---
 .../test/CIR/CodeGen/cleanup-conditional.cpp  |  2 +-
 .../CIR/CodeGen/cleanup-scope-goto-out.cpp    | 16 +++---
 .../CIR/CodeGen/cleanup-scope-goto-within.cpp |  8 +--
 clang/test/CIR/CodeGen/enum-bool.cpp          | 20 +++----
 clang/test/CIR/CodeGen/if.cpp                 |  8 +--
 clang/test/CIR/CodeGen/lambda-dtor-field.cpp  |  4 +-
 .../CIR/CodeGen/local-static-temp-dtor.cpp    |  2 +-
 .../CIR/CodeGen/new-delete-deactivation.cpp   |  8 +--
 .../CodeGen/X86/integer_argument_passing.c    | 34 ++++++------
 .../test/CodeGen/attr-counted-by-base-exprs.c |  2 +-
 .../linux-kernel-struct-union-initializer2.c  |  4 +-
 clang/test/CodeGen/mangle-windows.c           |  2 +-
 clang/test/CodeGen/pointer-arithmetic-align.c |  2 +-
 clang/test/CodeGen/regcall4.c                 |  4 +-
 clang/test/CodeGen/transparent-union-type.c   | 36 +++++++------
 clang/test/CodeGenCXX/new_hot_cold.cpp        | 16 +++---
 clang/test/CodeGenCXX/noreturn-init-stmt.cpp  |  4 +-
 llvm/include/llvm/ABI/FunctionInfo.h          | 25 ++++++---
 llvm/include/llvm/ABI/TargetInfo.h            | 15 +++++-
 llvm/lib/ABI/Targets/X86.cpp                  | 12 ++++-
 llvm/unittests/ABI/X86TargetInfoTest.cpp      | 53 +++++++++++++++++--
 mlir/include/mlir/ABI/ABIRewriteContext.h     | 14 +++--
 37 files changed, 334 insertions(+), 141 deletions(-)

diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 76eb04fd7c38c6..79fe8e9b6e6f58 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -553,7 +553,7 @@ CODEGENOPT(ZOSPPA1Name, 1, 1, Benign)
 /// Whether the function should extend small integer parameters: Direct,
 /// Conservative, Assumed, Default.
 ENUM_CODEGENOPT(ExtendIntegerArgs, ExtendIntegerArgsKind, 2,
-                ExtendIntegerArgsKind::Conservative)
+                ExtendIntegerArgsKind::Conservative, Benign)
 
 #undef CODEGENOPT
 #undef ENUM_CODEGENOPT
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 1348206f1738ad..89158cdb4df05f 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -182,6 +182,7 @@ struct MissingFeatures {
   static bool aggValueSlotMayOverlap() { return false; }
   static bool aggValueSlotVolatile() { return false; }
   static bool allocToken() { return false; }
+  static bool extendIntegerArgsOption() { return false; }
   static bool appleArm64CXXABI() { return false; }
   static bool appleKext() { return false; }
   static bool asmGoto() { return false; }
diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h
index c0ae231d568840..c24c67b77bfbb9 100644
--- a/clang/include/clang/CodeGen/CGFunctionInfo.h
+++ b/clang/include/clang/CodeGen/CGFunctionInfo.h
@@ -218,7 +218,10 @@ class ABIArgInfo {
     AI.setPaddingType(nullptr);
     AI.setDirectOffset(0);
     AI.setDirectAlign(0);
-    AI.setSignExt(Ty->hasSignedIntegerRepresentation());
+    if (Ty->hasSignedIntegerRepresentation())
+      AI.setSignExt(true);
+    else
+      AI.setZeroExt(true);
     return AI;
   }
 
@@ -396,16 +399,18 @@ class ABIArgInfo {
   }
 
   bool isZeroExt() const {
-    assert(isExtend() && (SignExt + ZeroExt <= 1) && "Invalid kind / flags!");
+    assert((isExtend() || isConservativeExtend()) && (SignExt + ZeroExt <= 1) &&
+           "Invalid kind / flags!");
     return ZeroExt;
   }
   void setZeroExt(bool ZExt) {
-    assert(isExtend() && "Invalid kind!");
+    assert((isExtend() || isConservativeExtend()) && "Invalid kind!");
     ZeroExt = ZExt;
   }
 
   bool isNoExt() const {
-    assert(isExtend() && (SignExt + ZeroExt <= 1) && "Invalid kind / flags!");
+    assert((isExtend() || isConservativeExtend()) && (SignExt + ZeroExt <= 1) &&
+           "Invalid kind / flags!");
     return !SignExt && !ZeroExt;
   }
 
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 7c00bada76ccf6..5f778107bc385f 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5799,7 +5799,7 @@ def mzos_hlq_clang_EQ : Joined<["-"], "mzos-hlq-clang=">, MetaVarName<"<ClangHLQ
 def mzos_hlq_csslib_EQ : Joined<["-"], "mzos-hlq-csslib=">, MetaVarName<"<CsslibHLQ>">,
   HelpText<"High level qualifier for z/OS CSSLIB dataset">;
 def mextend_small_integers_EQ : Joined<["-"], "mextend-small-integers=">,
-  Group<m_Group>, Flags<[CC1Option]>,
+  Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
   HelpText<"How to handle the small integer parameter: "
            "'none' (Pass the small integer parameter directly in caller) | "
            "'conservative' (Always extend small integer parameter in the caller but do not assume "
@@ -5809,7 +5809,35 @@ def mextend_small_integers_EQ : Joined<["-"], "mextend-small-integers=">,
   Values<"none,conservative,assumed,default">,
   NormalizedValuesScope<"CodeGenOptions::ExtendIntegerArgsKind">,
   NormalizedValues<["Direct", "Conservative", "Assumed", "Default"]>,
-  MarshallingInfoEnum<CodeGenOpts<"ExtendIntegerArgs">, "Conservative">;
+  MarshallingInfoEnum<CodeGenOpts<"ExtendIntegerArgs">, "Conservative">,
+  DocBrief<[{
+Specifies how to handle small integer arguments on i386 and x86_64
+targets that generally follow the System V ABI. The value must be 'none',
+'conservative', 'assumed', or 'default'. The default behavior
+depends on the target and can be explicitly requested with 'default'.
+
+In the past, on System V i386 and x86_64 targets, Clang passed promotable
+integer arguments (non-variadic arguments with types smaller than 'int')
+using a parameter convention in which the caller was assumed to have
+sign-extended or zero-extended the argument to the width of an 'int'. This
+convention did not conform to the documented ABI for these targets, which
+does not require the caller to perform this extension. This can introduce
+incompatibilities with code generated by other compilers on these targets.
+
+On most targets using the System V ABI, Clang no longer assumes that
+callers perform this extension. In order to maintain compatibility with
+code compiled by old versions of Clang, Clang will still perform the extension
+in the caller. This is the 'conservative' behavior. If compatibility with old
+Clang code is not required, extension in the caller can be disabled using
+'none', which may have minor performance and code-size benefits.
+
+On certain targets which use Clang as the system compiler, Clang continues
+to perform extension in the caller and assume it in in the callee. This is the
+behavior of 'assumed'. These platforms therefore diverge from the
+standard System V ABI. If compatibility with other compilers which do not
+recognize this divergence is required, 'conservative' may be used.
+Using 'none' on these targets is allowed but may lead to ABI mismatches.
+These targets include Apple and PlayStation platforms.}]>;
 def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group<m_Group>;
 def mno_global_merge : Flag<["-"], "mno-global-merge">, Group<m_Group>,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
index e18a2cb5d07d76..10a5bb5f9b7dfb 100644
--- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
@@ -671,13 +671,18 @@ convertABIArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx,
   }
   // An extended value is always read from byte 0 of its own storage, so
   // there is no offset to honor here.
-  if (info.isExtend()) {
+  // A conservative extension is performed by the caller, but the callee does
+  // not get to assume it, so its attribute only goes on call sites.
+  if (info.isExtend() || info.isConservativeExtend()) {
+    bool onCallSiteOnly = info.isConservativeExtend();
     if (isa_and_present<cir::BoolType>(origTy))
-      return ArgClassification::getExtend(nullptr, info.isSignExt());
+      return ArgClassification::getExtend(nullptr, info.isSignExt(),
+                                          onCallSiteOnly);
     assert((!origTy || isa<cir::IntType>(origTy)) &&
            "the x86_64 classifier only returns Extend for integers and bool");
     mlir::Type extendedTy = abiTypeToCIR(info.getCoerceToType(), ctx);
-    return ArgClassification::getExtend(extendedTy, info.isSignExt());
+    return ArgClassification::getExtend(extendedTy, info.isSignExt(),
+                                        onCallSiteOnly);
   }
   // ArgClassification has no address space for the indirect pointer yet.
   if (info.isIndirectAliased() ||
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
index c85f5421c21050..0a6c83d6f5ae42 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
@@ -212,18 +212,19 @@ static bool needsArgAttrUpdate(const FunctionClassification &fc) {
 }
 
 /// Build an updated arg_attrs ArrayAttr that drops Ignore'd args, adds
-/// llvm.signext / llvm.zeroext on Extend args, adds the pointer attributes
-/// for Indirect args in place of llvm.nofpclass, drops llvm.noundef from a
-/// coerced Direct arg that passes undefined bits, gives each field of a
-/// Direct+canFlatten argument the argument's attributes, and gives each field
-/// of an Expand argument an empty dict.  Direct and Extend slots keep their
-/// other existing attributes.  \p origArgTypes provides the pre-rewrite type
-/// for each arg slot.
+/// llvm.signext / llvm.zeroext on Extend args (only on call sites, as given by
+/// \p isCallSite, if the extension is not assumed by the callee), adds the
+/// pointer attributes for Indirect args in place of llvm.nofpclass, drops
+/// llvm.noundef from a coerced Direct arg that passes undefined bits, gives
+/// each field of a Direct+canFlatten argument the argument's attributes, and
+/// gives each field of an Expand argument an empty dict.  Direct and Extend
+/// slots keep their other existing attributes.  \p origArgTypes provides the
+/// pre-rewrite type for each arg slot.
 mlir::ArrayAttr updateArgAttrs(mlir::MLIRContext *ctx, mlir::ModuleOp module,
                                ArrayRef<mlir::Type> origArgTypes,
                                mlir::ArrayAttr existingArgAttrs,
                                const FunctionClassification &fc,
-                               const mlir::DataLayout &dl) {
+                               const mlir::DataLayout &dl, bool isCallSite) {
   mlir::Builder builder(ctx);
   SmallVector<mlir::Attribute> newArgAttrs;
   newArgAttrs.reserve(fc.argInfos.size());
@@ -248,7 +249,8 @@ mlir::ArrayAttr updateArgAttrs(mlir::MLIRContext *ctx, mlir::ModuleOp module,
       // fields, so each field gets an empty dict.
       auto recTy = cast<cir::RecordType>(origArgTypes[oldIdx]);
       newArgAttrs.append(recTy.getNumElements(), builder.getDictionaryAttr({}));
-    } else if (ac.kind == ArgKind::Extend) {
+    } else if (ac.kind == ArgKind::Extend &&
+               (isCallSite || !ac.extendOnCallSiteOnly)) {
       StringRef attrName = ac.signExtend
                                ? mlir::LLVM::LLVMDialect::getSExtAttrName()
                                : mlir::LLVM::LLVMDialect::getZExtAttrName();
@@ -1577,7 +1579,8 @@ mlir::LogicalResult rewriteIndirectReturnCall(
   mlir::ArrayAttr argAttrs = call->getAttrOfType<mlir::ArrayAttr>("arg_attrs");
   if (needsArgAttrUpdate(fc))
     argAttrs = updateArgAttrs(ctx, call->getParentOfType<mlir::ModuleOp>(),
-                              origCallArgTypes, argAttrs, fc, dl);
+                              origCallArgTypes, argAttrs, fc, dl,
+                              /*isCallSite=*/true);
   applySretSlotAttrs(newCall, argAttrs, origRetTy, sretAlign, builder);
 
   if (reuseStore) {
@@ -1929,7 +1932,8 @@ mlir::LogicalResult CIRABIRewriteContext::rewriteFunctionDefinition(
   if (hasSRet || needsArgAttrUpdate(fc)) {
     auto existing = funcOp->getAttrOfType<mlir::ArrayAttr>("arg_attrs");
     mlir::ArrayAttr updated =
-        updateArgAttrs(ctx, module, oldArgTypes, existing, fc, dl);
+        updateArgAttrs(ctx, module, oldArgTypes, existing, fc, dl,
+                       /*isCallSite=*/false);
     if (hasSRet) {
       // Prepend the sret slot's attribute dict (slot 0); the per-argument
       // dicts shift to slots 1..N.  noalias is valid only on the callee's
@@ -2236,8 +2240,9 @@ CIRABIRewriteContext::rewriteCallSite(mlir::Operation *callOp,
 
   if (needsArgAttrUpdate(fc)) {
     auto existing = call->getAttrOfType<mlir::ArrayAttr>("arg_attrs");
-    newCall->setAttr("arg_attrs", updateArgAttrs(ctx, module, origCallArgTypes,
-                                                 existing, fc, dl));
+    newCall->setAttr("arg_attrs",
+                     updateArgAttrs(ctx, module, origCallArgTypes, existing, fc,
+                                    dl, /*isCallSite=*/true));
   }
   // Add llvm.signext / llvm.zeroext to an Extend return, and drop llvm.noundef
   // from a coerced Direct return that passes undefined bits.
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp
index 6e75ce03d14ffd..7b82978ead0fe3 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/Passes.h"
+#include "clang/CIR/MissingFeatures.h"
 #include "llvm/Support/TimeProfiler.h"
 #include "llvm/TargetParser/Triple.h"
 
@@ -67,6 +68,10 @@ getX86ABICompatInfo(const llvm::Triple &triple,
       compat > clang::LangOptions::ClangABI::Ver20 && !triple.isPS();
   abiCompat.Clang11Compat =
       compat <= clang::LangOptions::ClangABI::Ver11 || triple.isPS();
+  // Match the classic CodeGen default of -mextend-small-integers.
+  assert(!cir::MissingFeatures::extendIntegerArgsOption());
+  abiCompat.ExtendIntegerArgs =
+      llvm::abi::X86ExtendIntegerArgsKind::Conservative;
   return abiCompat;
 }
 
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index bae1a950454a4e..67097fbca8b11c 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -876,6 +876,8 @@ static const char *abiKindToString(ABIArgInfo::Kind K) {
     return "Direct";
   case ABIArgInfo::Extend:
     return "Extend";
+  case ABIArgInfo::ConservativeExtend:
+    return "ConservativeExtend";
   case ABIArgInfo::Indirect:
     return "Indirect";
   case ABIArgInfo::IndirectAliased:
@@ -963,6 +965,7 @@ void CodeGenModule::computeABIInfoUsingLib(CGFunctionInfo &FI) {
 
     switch (Res.getKind()) {
     case ABIArgInfo::Extend:
+    case ABIArgInfo::ConservativeExtend:
       CheckSimple(Target.isSignExt(), Res.isSignExt(), "SignExt");
       CheckSimple(Target.isZeroExt(), Res.isZeroExt(), "ZeroExt");
       [[fallthrough]];
@@ -1040,6 +1043,18 @@ ABIArgInfo CodeGenModule::convertABIArgInfo(const llvm::abi::ArgInfo &AbiInfo,
                                  /*Padding=*/nullptr,
                                  AbiInfo.getCanBeFlattened(), DirectAlign);
   }
+  case llvm::abi::ArgInfo::ConservativeExtend: {
+    llvm::Type *CoercedType = nullptr;
+    if (AbiInfo.getCoerceToType())
+      CoercedType = AbiReverseMapper->convertType(AbiInfo.getCoerceToType());
+    if (!CoercedType)
+      CoercedType = getTypes().ConvertType(Type);
+    ABIArgInfo AI = ABIArgInfo::getConservativeExtend(
+        useFirstFieldIfTransparentUnion(Type), CoercedType);
+    AI.setSignExt(AbiInfo.isSignExt());
+    AI.setZeroExt(AbiInfo.isZeroExt());
+    return AI;
+  }
   case llvm::abi::ArgInfo::Extend: {
     llvm::Type *CoercedType = nullptr;
     if (AbiInfo.getCoerceToType())
@@ -2639,7 +2654,9 @@ static bool DetermineNoUndef(QualType QTy, CodeGenTypes &Types,
   if (AI.getKind() == ABIArgInfo::Indirect ||
       AI.getKind() == ABIArgInfo::IndirectAliased)
     return true;
-  if (AI.getKind() == ABIArgInfo::Extend && !AI.isNoExt())
+  if ((AI.getKind() == ABIArgInfo::Extend ||
+       AI.getKind() == ABIArgInfo::ConservativeExtend) &&
+      !AI.isNoExt())
     return true;
   if (!DL.typeSizeEqualsStoreSize(Ty))
     // TODO: This will result in a modest amount of values not marked noundef
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index eec4d9e714abe6..f609a54f789ba0 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -392,7 +392,8 @@ static void initializeCommonABICompatInfo(llvm::abi::ABICompatInfo &CompatInfo,
 
 static void initializeX86ABICompatInfo(llvm::abi::X86ABICompatInfo &CompatInfo,
                                        const llvm::Triple &T,
-                                       const LangOptions::ClangABI Compat) {
+                                       const LangOptions::ClangABI Compat,
+                                       const CodeGenOptions &CGOpts) {
   initializeCommonABICompatInfo(CompatInfo, Compat);
   CompatInfo.ClassifyIntegerMMXAsSSE = Compat > LangOptions::ClangABI::Ver3_8 &&
                                        !T.isOSDarwin() && !T.isPS() &&
@@ -406,6 +407,19 @@ static void initializeX86ABICompatInfo(llvm::abi::X86ABICompatInfo &CompatInfo,
   CompatInfo.Clang11Compat = Compat <= LangOptions::ClangABI::Ver11 || T.isPS();
   CompatInfo.ClassifyUnnamedBitFields =
       Compat > LangOptions::ClangABI::Ver23 && !T.isPS();
+  switch (CGOpts.getExtendIntegerArgs()) {
+  case CodeGenOptions::ExtendIntegerArgsKind::Assumed:
+    CompatInfo.ExtendIntegerArgs = llvm::abi::X86ExtendIntegerArgsKind::Assumed;
+    break;
+  case CodeGenOptions::ExtendIntegerArgsKind::Conservative:
+    CompatInfo.ExtendIntegerArgs =
+        llvm::abi::X86ExtendIntegerArgsKind::Conservative;
+    break;
+  case CodeGenOptions::ExtendIntegerArgsKind::Direct:
+  case CodeGenOptions::ExtendIntegerArgsKind::Default:
+    CompatInfo.ExtendIntegerArgs = llvm::abi::X86ExtendIntegerArgsKind::Direct;
+    break;
+  }
 }
 
 const llvm::abi::TargetInfo &
@@ -462,8 +476,8 @@ CodeGenModule::getLLVMABITargetInfo(llvm::abi::TypeBuilder &TB) {
                         : llvm::abi::X86AVXABILevel::None;
 
     llvm::abi::X86ABICompatInfo CompatInfo;
-    initializeX86ABICompatInfo(CompatInfo, T,
-                               getLangOpts().getClangABICompat());
+    initializeX86ABICompatInfo(CompatInfo, T, getLangOpts().getClangABICompat(),
+                               getCodeGenOpts());
 
     bool Has64BitPointers = getTarget().getPointerWidth(LangAS::Default) == 64;
 
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index bf9e0d223d243d..bab1655820f5bf 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -1002,7 +1002,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State,
                  ? ABIArgInfo::getConservativeExtendInReg(Ty, CGT.ConvertType(Ty))
                  : ABIArgInfo::getConservativeExtend(Ty, CGT.ConvertType(Ty));
     case CodeGenOptions::ExtendIntegerArgsKind::Direct:
-    // ExtendIntegerArgsKind::Direct will be handled at the last.
+    case CodeGenOptions::ExtendIntegerArgsKind::Default:
+      // ExtendIntegerArgsKind::Direct will be handled at the last.
       break;
     }
   }
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index c4a8525b25d6b2..a8f12dd7a21561 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7462,11 +7462,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                      options::OPT_mno_stack_arg_probe);
 
   // TODO: Support 'default' for OPT_mextend_small_integers_EQ
-  if (Args.getLastArgValue(options::OPT_mextend_small_integers_EQ) == "default")
-    D.Diag(diag::err_drv_unsupported_option_argument)
-        << "mextend-small-integers"
-        << "default";
-  Args.AddLastArg(CmdArgs, options::OPT_mextend_small_integers_EQ);
+  if (Arg *A = Args.getLastArg(options::OPT_mextend_small_integers_EQ)) {
+    if (StringRef(A->getValue()) == "default")
+      D.Diag(diag::err_drv_unsupported_option_argument)
+          << A->getSpelling() << A->getValue();
+    else
+      A->render(Args, CmdArgs);
+  }
 
   if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
                                options::OPT_mno_restrict_it)) {
diff --git a/clang/test/CIR/CodeGen/attr-noundef.cpp b/clang/test/CIR/CodeGen/attr-noundef.cpp
index c487304c0e9a94..d4f49bfa8e2704 100644
--- a/clang/test/CIR/CodeGen/attr-noundef.cpp
+++ b/clang/test/CIR/CodeGen/attr-noundef.cpp
@@ -241,6 +241,6 @@ void pass_large_BitInt(_BitInt(127) e) {
 // CIR-LABEL: cir.func {{.*}} @_ZN12check_exotic17pass_large_BitIntEDB127_(%arg0: !u64i {llvm.noundef} loc({{.+}}), %arg1: !u64i {llvm.noundef} loc(
 
 // LLVM: define dso_local noundef i3 @_ZN12check_exotic10ret_BitIntEv()
-// LLVM: define dso_local void @_ZN12check_exotic11pass_BitIntEDB3_(i3 noundef signext %
+// LLVM: define dso_local void @_ZN12check_exotic11pass_BitIntEDB3_(i3 noundef %
 // LLVM: define dso_local void @_ZN12check_exotic17pass_large_BitIntEDB127_(i64 noundef %{{.+}}, i64 noundef %
 } // namespace check_exotic
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c
index 082488b6ba4d92..f987d061fb39a9 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-packed.c
@@ -127,9 +127,9 @@ int take_five_short(FiveShort v) { return v.b; }
 FiveShort ret_five_short(short x) { FiveShort v = {0, x, 0}; return v; }
 
 // CIR: cir.func{{.*}} @take_five_short(%arg0: !cir.int<u, 40>{{.*}}) -> !s32i
-// CIR: cir.func{{.*}} @ret_five_short(%arg0: !s16i {llvm.noundef, llvm.signext}{{.*}}) -> !cir.int<u, 40>
+// CIR: cir.func{{.*}} @ret_five_short(%arg0: !s16i {llvm.noundef}{{.*}}) -> !cir.int<u, 40>
 // LLVM: define dso_local i32 @take_five_short(i40 %{{.+}})
-// LLVM: define dso_local i40 @ret_five_short(i16 noundef signext %{{.+}})
+// LLVM: define dso_local i40 @ret_five_short(i16 noundef %{{.+}})
 
 // A named access unit is only ambiguous where padding lets classic read the
 // declared type through the gap, so a packed record whose every byte holds
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
index bd2750df88136d..211c3ed001af3a 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64-variadic.c
@@ -190,14 +190,14 @@ int call_wide_char(Pair2 p, WideChar w) { return vf(p, w); }
 // declared parameter.
 int ell_bitint17(Pair2 p, _BitInt(17) b) { return vf(p, b); }
 
-// CIR-LABEL: cir.func {{.*}}@ell_bitint17(%arg0: !u64i loc({{.+}}), %arg1: !cir.int<s, 17, bitint> {llvm.noundef, llvm.signext} loc({{.+}})) -> !s32i
+// CIR-LABEL: cir.func {{.*}}@ell_bitint17(%arg0: !u64i loc({{.+}}), %arg1: !cir.int<s, 17, bitint> {llvm.noundef} loc({{.+}})) -> !s32i
 // CIR:         cir.store %arg1, %[[BSLOT:[0-9]+]] : !cir.int<s, 17, bitint>, !cir.ptr<!cir.int<s, 17, bitint>>
 // CIR:         %[[BV:[0-9]+]] = cir.load align(4) %[[BSLOT]] : !cir.ptr<!cir.int<s, 17, bitint>>, !cir.int<s, 17, bitint>
 // CIR:         %[[PV:[0-9]+]] = cir.load align(4) %{{[0-9]+}} : !cir.ptr<!u64i>, !u64i
 // CIR:         cir.call @vf(%[[PV]], %[[BV]]) : (!u64i, !cir.int<s, 17, bitint> {llvm.noundef, llvm.signext}) -> !s32i
 
 // LLVM-LABEL: define dso_local i32 @ell_bitint17(
-// LLVM-SAME:    i64 %[[P:[0-9a-zA-Z._]+]], i17 noundef signext %[[B:[0-9a-zA-Z._]+]])
+// LLVM-SAME:    i64 %[[P:[0-9a-zA-Z._]+]], i17 noundef %[[B:[0-9a-zA-Z._]+]])
 // LLVM:         %[[EXT:[0-9a-zA-Z._]+]] = sext i17 %[[B]] to i32
 // LLVM:         store i32 %[[EXT]], ptr %[[BSLOT:[0-9a-zA-Z._]+]], align 4
 // LLVM:         %[[RE:[0-9a-zA-Z._]+]] = load i32, ptr %[[BSLOT]], align 4
diff --git a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64.c b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64.c
index 511c677147a4b0..946d25024fb6bb 100644
--- a/clang/test/CIR/CodeGen/call-conv-lowering-x86_64.c
+++ b/clang/test/CIR/CodeGen/call-conv-lowering-x86_64.c
@@ -29,14 +29,27 @@ typedef union { char c[32]; } __attribute__((aligned(32))) UBigOverAligned;
 // Narrow signed integer sign-extended in a register.
 signed char ext_schar(signed char c) { return c; }
 
-// CIR: cir.func {{.*}}@ext_schar(%arg0: !s8i {{.*}}llvm.signext{{.*}}) -> !s8i
-// LLVM: define dso_local i8 @ext_schar(i8 noundef signext %{{.+}})
+// CIR: cir.func {{.*}}@ext_schar(%arg0: !s8i {llvm.noundef}{{.*}}) -> !s8i
+// LLVM: define dso_local i8 @ext_schar(i8 noundef %{{.+}})
 
 // Narrow unsigned integer zero-extended in a register.
 unsigned char ext_uchar(unsigned char c) { return c; }
 
-// CIR: cir.func {{.*}}@ext_uchar(%arg0: !u8i {{.*}}llvm.zeroext{{.*}}) -> !u8i
-// LLVM: define dso_local i8 @ext_uchar(i8 noundef zeroext %{{.+}})
+// CIR: cir.func {{.*}}@ext_uchar(%arg0: !u8i {llvm.noundef}{{.*}}) -> !u8i
+// LLVM: define dso_local i8 @ext_uchar(i8 noundef %{{.+}})
+
+// The caller extends a narrow integer argument, but the callee does not get to
+// assume that it did, so only the call site carries signext/zeroext.
+int call_ext(signed char c, unsigned char uc) {
+  return ext_schar(c) + ext_uchar(uc);
+}
+
+// CIR-LABEL: cir.func {{.*}}@call_ext(%arg0: !s8i {llvm.noundef}{{.*}}, %arg1: !u8i {llvm.noundef}{{.*}}) -> !s32i
+// CIR: cir.call @ext_schar(%{{.+}}) : (!s8i {llvm.noundef, llvm.signext}) -> !s8i
+// CIR: cir.call @ext_uchar(%{{.+}}) : (!u8i {llvm.noundef, llvm.zeroext}) -> !u8i
+// LLVM-LABEL: define dso_local i32 @call_ext(i8 noundef %{{.+}}, i8 noundef %{{.+}})
+// LLVM: call i8 @ext_schar(i8 noundef signext %{{.+}})
+// LLVM: call i8 @ext_uchar(i8 noundef zeroext %{{.+}})
 
 // Floating-point scalar passed/returned in an SSE register.
 double sse_double(double d) { return d; }
@@ -166,7 +179,7 @@ UBytes12 ret_union_bytes(char c) {
   return u;
 }
 
-// CIR: cir.func {{.*}}@ret_union_bytes(%arg0: !s8i {llvm.noundef, llvm.signext}{{.*}}) -> ![[I64I32]]
+// CIR: cir.func {{.*}}@ret_union_bytes(%arg0: !s8i {llvm.noundef}{{.*}}) -> ![[I64I32]]
 // CIR:   %[[SLOT:.+]] = cir.alloca "coerce" align(8) : !cir.ptr<![[I64I32]]>
 // CIR:   %[[U:.+]] = cir.alloca "__retval" align(4) : !cir.ptr<!rec_UBytes12>
 // CIR:   %[[SLOT_U:.+]] = cir.cast bitcast %[[SLOT]] : !cir.ptr<![[I64I32]]> -> !cir.ptr<!rec_UBytes12>
@@ -174,7 +187,7 @@ UBytes12 ret_union_bytes(char c) {
 // CIR-NEXT:   %[[RET:.+]] = cir.load align(8) %[[SLOT]] : !cir.ptr<![[I64I32]]>, ![[I64I32]]
 // CIR-NEXT:   cir.return %[[RET]] : ![[I64I32]]
 
-// LLVM: define dso_local { i64, i32 } @ret_union_bytes(i8 noundef signext %{{.+}})
+// LLVM: define dso_local { i64, i32 } @ret_union_bytes(i8 noundef %{{.+}})
 // LLVM:   getelementptr inbounds nuw %struct.CharIntInt, ptr %[[U:.+]], i32 0, i32 0
 // LLVM:   %[[B1:.+]] = getelementptr inbounds nuw %struct.TwoChars, ptr %[[U]], i32 0, i32 1
 // LLVM-NEXT:   store i8 %{{.+}}, ptr %[[B1]], align 1
diff --git a/clang/test/CIR/CodeGen/cleanup-conditional.cpp b/clang/test/CIR/CodeGen/cleanup-conditional.cpp
index b9df861d17e4f3..b47f60a40849c4 100644
--- a/clang/test/CIR/CodeGen/cleanup-conditional.cpp
+++ b/clang/test/CIR/CodeGen/cleanup-conditional.cpp
@@ -806,7 +806,7 @@ _Complex float test_complex_cond_cleanup(bool b, _Complex float x) {
 // CIR:     cir.yield
 // CIR:   }
 
-// LLVMCIR-LABEL: define dso_local {{.*}} <2 x float> @_Z25test_complex_cond_cleanupbCf(i1 noundef zeroext %{{.*}}, <2 x float> noundef %{{.*}})
+// LLVMCIR-LABEL: define dso_local {{.*}} <2 x float> @_Z25test_complex_cond_cleanupbCf(i1 noundef %{{.*}}, <2 x float> noundef %{{.*}})
 // LLVMCIR:         %[[TMP:.*]] = alloca %struct.CplxD
 // LLVMCIR:         %[[ACTIVE:.*]] = alloca i8
 // LLVMCIR:         br i1 %{{.*}}, label %[[TRUE_BR:.*]], label %[[FALSE_BR:.*]]
diff --git a/clang/test/CIR/CodeGen/cleanup-scope-goto-out.cpp b/clang/test/CIR/CodeGen/cleanup-scope-goto-out.cpp
index 76ac8e4d38c607..6941d7b2055e1b 100644
--- a/clang/test/CIR/CodeGen/cleanup-scope-goto-out.cpp
+++ b/clang/test/CIR/CodeGen/cleanup-scope-goto-out.cpp
@@ -38,7 +38,7 @@ end:;
 // CIR:         cir.label "end"
 // CIR:         cir.return
 
-// LLVM-LABEL: define dso_local void @_Z19test_goto_only_exitb(i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local void @_Z19test_goto_only_exitb(i1 noundef %{{[^,)]+}})
 // LLVM:         %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor
 // LLVM:         br i1 %{{.*}}, label %[[IF_THEN:.*]], label %[[IF_END:.*]]
 // LLVM:       [[IF_THEN]]:
@@ -57,7 +57,7 @@ end:;
 // LLVM:       [[END]]:
 // LLVM:         ret void
 
-// OGCG-LABEL: define dso_local void @_Z19test_goto_only_exitb(i1 noundef zeroext %{{.*}})
+// OGCG-LABEL: define dso_local void @_Z19test_goto_only_exitb(i1 noundef %{{.*}})
 // OGCG:         %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor
 // OGCG:         br i1 %{{.*}}, label %if.then, label %if.end
 // OGCG:       if.then:
@@ -101,7 +101,7 @@ end:;
 // CIR:         cir.label "end"
 // CIR:         cir.return
 
-// LLVM-LABEL: define dso_local void @_Z27test_goto_among_other_exitsb(i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local void @_Z27test_goto_among_other_exitsb(i1 noundef %{{[^,)]+}})
 // LLVM:         %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor
 // LLVM:         br i1 %{{.*}}, label %[[GOTO_PATH:.*]], label %[[NORMAL_PATH:.*]]
 // LLVM:       [[GOTO_PATH]]:
@@ -125,7 +125,7 @@ end:;
 // LLVM:       [[END]]:
 // LLVM:         ret void
 
-// OGCG-LABEL: define dso_local void @_Z27test_goto_among_other_exitsb(i1 noundef zeroext %{{.*}})
+// OGCG-LABEL: define dso_local void @_Z27test_goto_among_other_exitsb(i1 noundef %{{.*}})
 // OGCG:         %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor
 // OGCG:         br i1 %{{.*}}, label %if.then, label %if.end
 // OGCG:       if.then:
@@ -186,7 +186,7 @@ void test_goto_inner_to_outer(bool cond) {
 // CIR:         }
 // CIR:         cir.return
 
-// LLVM-LABEL: define dso_local void @_Z24test_goto_inner_to_outerb(i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local void @_Z24test_goto_inner_to_outerb(i1 noundef %{{[^,)]+}})
 // LLVM:         alloca %struct.StructWithDestructor
 // LLVM:         alloca %struct.StructWithDestructor
 // LLVM:         br i1 %{{.*}}, label %[[GOTO_PATH:.*]], label %[[NORMAL_PATH:.*]]
@@ -217,7 +217,7 @@ void test_goto_inner_to_outer(bool cond) {
 // LLVM-NOT:     call void @_ZN20StructWithDestructorD1Ev
 // LLVM:         ret void
 
-// OGCG-LABEL: define dso_local void @_Z24test_goto_inner_to_outerb(i1 noundef zeroext %{{.*}})
+// OGCG-LABEL: define dso_local void @_Z24test_goto_inner_to_outerb(i1 noundef %{{.*}})
 // OGCG:         %[[OUTER_ADDR:.*]] = alloca %struct.StructWithDestructor
 // OGCG:         %[[INNER_ADDR:.*]] = alloca %struct.StructWithDestructor
 // OGCG:         br i1 %{{.*}}, label %if.then, label %if.end
@@ -285,7 +285,7 @@ end:;
 // CIR:         cir.label "end"
 // CIR:         cir.return
 
-// LLVM-LABEL: define dso_local void @_Z27test_goto_out_of_two_nestedb(i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local void @_Z27test_goto_out_of_two_nestedb(i1 noundef %{{[^,)]+}})
 // LLVM:         %[[OUTER_ADDR:.*]] = alloca %struct.StructWithDestructor
 // LLVM:         %[[INNER_ADDR:.*]] = alloca %struct.StructWithDestructor
 // LLVM:         br i1 %{{.*}}, label %[[GOTO_PATH:.*]], label %[[NORMAL_PATH:.*]]
@@ -325,7 +325,7 @@ end:;
 // LLVM:       [[END]]:
 // LLVM:         ret void
 
-// OGCG-LABEL: define dso_local void @_Z27test_goto_out_of_two_nestedb(i1 noundef zeroext %{{.*}})
+// OGCG-LABEL: define dso_local void @_Z27test_goto_out_of_two_nestedb(i1 noundef %{{.*}})
 // OGCG:         %[[OUTER_ADDR:.*]] = alloca %struct.StructWithDestructor
 // OGCG:         %[[INNER_ADDR:.*]] = alloca %struct.StructWithDestructor
 // OGCG:         br i1 %{{.*}}, label %if.then, label %if.end
diff --git a/clang/test/CIR/CodeGen/cleanup-scope-goto-within.cpp b/clang/test/CIR/CodeGen/cleanup-scope-goto-within.cpp
index 2d6a3223883b92..5e35c8933909dc 100644
--- a/clang/test/CIR/CodeGen/cleanup-scope-goto-within.cpp
+++ b/clang/test/CIR/CodeGen/cleanup-scope-goto-within.cpp
@@ -40,7 +40,7 @@ void test_goto_within_cleanup(bool cond) {
 // CIR:         }
 // CIR:         cir.return
 
-// LLVM-LABEL: define dso_local void @_Z24test_goto_within_cleanupb(i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local void @_Z24test_goto_within_cleanupb(i1 noundef %{{[^,)]+}})
 // LLVM:         %[[COND_ADDR:.*]] = alloca i8
 // LLVM:         %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor
 // LLVM:         %[[COND_BYTE:.*]] = load i8, ptr %[[COND_ADDR]]
@@ -61,7 +61,7 @@ void test_goto_within_cleanup(bool cond) {
 // LLVM-NOT:     call void @_ZN20StructWithDestructorD1Ev
 // LLVM:         ret void
 
-// OGCG-LABEL: define dso_local void @_Z24test_goto_within_cleanupb(i1 noundef zeroext %cond)
+// OGCG-LABEL: define dso_local void @_Z24test_goto_within_cleanupb(i1 noundef %cond)
 // OGCG:         %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor
 // OGCG:         br i1 %{{.*}}, label %if.then, label %if.end
 // OGCG:       if.then:
@@ -111,7 +111,7 @@ void test_goto_jump_into_nested_op(bool cond1, bool cond2) {
 // CIR:         }
 // CIR:         cir.return
 
-// LLVM-LABEL: define dso_local void @_Z29test_goto_jump_into_nested_opbb(i1 noundef zeroext %{{[^,)]+}}, i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local void @_Z29test_goto_jump_into_nested_opbb(i1 noundef %{{[^,)]+}}, i1 noundef %{{[^,)]+}})
 // LLVM:         %[[COND1_ADDR:.*]] = alloca i8
 // LLVM:         %[[COND2_ADDR:.*]] = alloca i8
 // LLVM:         %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor
@@ -141,7 +141,7 @@ void test_goto_jump_into_nested_op(bool cond1, bool cond2) {
 // LLVM-NOT:     call void @_ZN20StructWithDestructorD1Ev
 // LLVM:         ret void
 
-// OGCG-LABEL: define dso_local void @_Z29test_goto_jump_into_nested_opbb(i1 noundef zeroext %cond1, i1 noundef zeroext %cond2)
+// OGCG-LABEL: define dso_local void @_Z29test_goto_jump_into_nested_opbb(i1 noundef %cond1, i1 noundef %cond2)
 // OGCG:         %[[COND1_ADDR:.*]] = alloca i8
 // OGCG:         %[[COND2_ADDR:.*]] = alloca i8
 // OGCG:         %[[A_ADDR:.*]] = alloca %struct.StructWithDestructor
diff --git a/clang/test/CIR/CodeGen/enum-bool.cpp b/clang/test/CIR/CodeGen/enum-bool.cpp
index 8dce4fabc6dc2c..276b057e90be88 100644
--- a/clang/test/CIR/CodeGen/enum-bool.cpp
+++ b/clang/test/CIR/CodeGen/enum-bool.cpp
@@ -28,7 +28,7 @@ void storeEnum(BoolEnum *p, BoolEnum v) { *p = v; }
 // CIR:         %[[P:.*]] = cir.load deref {{.*}} : !cir.ptr<!cir.ptr<!cir.bool>>, !cir.ptr<!cir.bool>
 // CIR:         cir.store {{.*}}%[[V]], %[[P]] : !cir.bool, !cir.ptr<!cir.bool>
 
-// LLVM-LABEL: define dso_local void @_Z9storeEnumP8BoolEnumS_(ptr noundef %{{[^,)]+}}, i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local void @_Z9storeEnumP8BoolEnumS_(ptr noundef %{{[^,)]+}}, i1 noundef %{{[^,)]+}})
 // LLVM:         zext i1 %{{.*}} to i8
 // LLVM:         store i8 %{{.*}}, ptr %{{.*}}, align 1
 // LLVM:         load i8, ptr %{{.*}}, align 1
@@ -42,7 +42,7 @@ bool toBool(BoolEnum e) { return static_cast<bool>(e); }
 // CIR-NOT:     cir.cast int_to_bool
 // CIR:         cir.return
 
-// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6toBool8BoolEnum(i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6toBool8BoolEnum(i1 noundef %{{[^,)]+}})
 // LLVM:         ret i1 %{{.*}}
 
 // An unscoped enum is integer-promoted before the comparison, so cir.cmp sees
@@ -54,7 +54,7 @@ bool ltUnscopedEnum(BoolEnum a, BoolEnum b) { return a < b; }
 // CIR:         %[[B:.*]] = cir.cast bool_to_int %{{.*}} : !cir.bool -> !s32i
 // CIR:         cir.cmp lt %[[A]], %[[B]] : !s32i
 
-// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z14ltUnscopedEnum8BoolEnumS_(i1 noundef zeroext %{{[^,)]+}}, i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z14ltUnscopedEnum8BoolEnumS_(i1 noundef %{{[^,)]+}}, i1 noundef %{{[^,)]+}})
 // LLVM:         zext i1 %{{.*}} to i32
 // LLVM:         zext i1 %{{.*}} to i32
 // LLVM:         icmp slt i32 %{{.*}}, %{{.*}}
@@ -67,7 +67,7 @@ bool ltPlainBool(bool a, bool b) { return a < b; }
 // CIR:         %[[B:.*]] = cir.cast bool_to_int %{{.*}} : !cir.bool -> !s32i
 // CIR:         cir.cmp lt %[[A]], %[[B]] : !s32i
 
-// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z11ltPlainBoolbb(i1 noundef zeroext %{{[^,)]+}}, i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z11ltPlainBoolbb(i1 noundef %{{[^,)]+}}, i1 noundef %{{[^,)]+}})
 // LLVM:         zext i1 %{{.*}} to i32
 // LLVM:         zext i1 %{{.*}} to i32
 // LLVM:         icmp slt i32 %{{.*}}, %{{.*}}
@@ -81,7 +81,7 @@ bool eqEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a == b; }
 // CIR-LABEL: cir.func{{.*}} @_Z6eqEnum14ScopedBoolEnumS_
 // CIR:         cir.cmp eq %{{.*}}, %{{.*}} : !cir.bool
 
-// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6eqEnum14ScopedBoolEnumS_(i1 noundef zeroext %{{[^,)]+}}, i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6eqEnum14ScopedBoolEnumS_(i1 noundef %{{[^,)]+}}, i1 noundef %{{[^,)]+}})
 // LLVM:         icmp eq i1 %{{.*}}, %{{.*}}
 
 bool neEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a != b; }
@@ -89,7 +89,7 @@ bool neEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a != b; }
 // CIR-LABEL: cir.func{{.*}} @_Z6neEnum14ScopedBoolEnumS_
 // CIR:         cir.cmp ne %{{.*}}, %{{.*}} : !cir.bool
 
-// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6neEnum14ScopedBoolEnumS_(i1 noundef zeroext %{{[^,)]+}}, i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6neEnum14ScopedBoolEnumS_(i1 noundef %{{[^,)]+}}, i1 noundef %{{[^,)]+}})
 // LLVM:         icmp ne i1 %{{.*}}, %{{.*}}
 
 bool ltEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a < b; }
@@ -97,7 +97,7 @@ bool ltEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a < b; }
 // CIR-LABEL: cir.func{{.*}} @_Z6ltEnum14ScopedBoolEnumS_
 // CIR:         cir.cmp lt %{{.*}}, %{{.*}} : !cir.bool
 
-// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6ltEnum14ScopedBoolEnumS_(i1 noundef zeroext %{{[^,)]+}}, i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6ltEnum14ScopedBoolEnumS_(i1 noundef %{{[^,)]+}}, i1 noundef %{{[^,)]+}})
 // LLVM:         icmp ult i1 %{{.*}}, %{{.*}}
 
 bool leEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a <= b; }
@@ -105,7 +105,7 @@ bool leEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a <= b; }
 // CIR-LABEL: cir.func{{.*}} @_Z6leEnum14ScopedBoolEnumS_
 // CIR:         cir.cmp le %{{.*}}, %{{.*}} : !cir.bool
 
-// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6leEnum14ScopedBoolEnumS_(i1 noundef zeroext %{{[^,)]+}}, i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6leEnum14ScopedBoolEnumS_(i1 noundef %{{[^,)]+}}, i1 noundef %{{[^,)]+}})
 // LLVM:         icmp ule i1 %{{.*}}, %{{.*}}
 
 bool gtEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a > b; }
@@ -113,7 +113,7 @@ bool gtEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a > b; }
 // CIR-LABEL: cir.func{{.*}} @_Z6gtEnum14ScopedBoolEnumS_
 // CIR:         cir.cmp gt %{{.*}}, %{{.*}} : !cir.bool
 
-// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6gtEnum14ScopedBoolEnumS_(i1 noundef zeroext %{{[^,)]+}}, i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6gtEnum14ScopedBoolEnumS_(i1 noundef %{{[^,)]+}}, i1 noundef %{{[^,)]+}})
 // LLVM:         icmp ugt i1 %{{.*}}, %{{.*}}
 
 bool geEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a >= b; }
@@ -121,5 +121,5 @@ bool geEnum(ScopedBoolEnum a, ScopedBoolEnum b) { return a >= b; }
 // CIR-LABEL: cir.func{{.*}} @_Z6geEnum14ScopedBoolEnumS_
 // CIR:         cir.cmp ge %{{.*}}, %{{.*}} : !cir.bool
 
-// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6geEnum14ScopedBoolEnumS_(i1 noundef zeroext %{{[^,)]+}}, i1 noundef zeroext %{{[^,)]+}})
+// LLVM-LABEL: define dso_local noundef zeroext i1 @_Z6geEnum14ScopedBoolEnumS_(i1 noundef %{{[^,)]+}}, i1 noundef %{{[^,)]+}})
 // LLVM:         icmp uge i1 %{{.*}}, %{{.*}}
diff --git a/clang/test/CIR/CodeGen/if.cpp b/clang/test/CIR/CodeGen/if.cpp
index 12c35a175650be..729f75a3708823 100644
--- a/clang/test/CIR/CodeGen/if.cpp
+++ b/clang/test/CIR/CodeGen/if.cpp
@@ -26,7 +26,7 @@ int if0(bool a) {
 // CIR-NEXT:  }
 
 
-// LLVM: define{{.*}} i32 @_Z3if0b(i1 noundef zeroext %0)
+// LLVM: define{{.*}} i32 @_Z3if0b(i1 noundef %0)
 // LLVM:   br label %[[ENTRY:.*]]
 // LLVM: [[ENTRY]]:
 // LLVM:   %6 = load i8, ptr %3, align 1
@@ -43,7 +43,7 @@ int if0(bool a) {
 // LLVM:   %12 = load i32, ptr %2, align 4
 // LLVM:   ret i32 %12
 
-// OGCG: define{{.*}} i32 @_Z3if0b(i1 noundef zeroext %a)
+// OGCG: define{{.*}} i32 @_Z3if0b(i1 noundef %a)
 // OGCG: entry:
 // OGCG:   %[[RETVAL:.*]] = alloca i32, align 4
 // OGCG:   %[[A_ADDR:.*]] = alloca i8, align 1
@@ -165,7 +165,7 @@ void if2(int a, bool b, bool c) {
 // CIR:   }
 // CIR: }
 
-// LLVM: define{{.*}} void @_Z3if2ibb(i32 noundef %[[A:.*]], i1 noundef zeroext %[[B:.*]], i1 noundef zeroext %[[C:.*]])
+// LLVM: define{{.*}} void @_Z3if2ibb(i32 noundef %[[A:.*]], i1 noundef %[[B:.*]], i1 noundef %[[C:.*]])
 // LLVM:   %[[VARA:.*]] = alloca i32, align 4
 // LLVM:   %[[VARB:.*]] = alloca i8, align 1
 // LLVM:   %[[VARC:.*]] = alloca i8, align 1
@@ -214,7 +214,7 @@ void if2(int a, bool b, bool c) {
 // LLVM: [[LABEL28]]:
 // LLVM:   ret void
 
-// OGCG: define{{.*}} void @_Z3if2ibb(i32 noundef %[[A:.*]], i1 noundef zeroext %[[B:.*]], i1 noundef zeroext %[[C:.*]])
+// OGCG: define{{.*}} void @_Z3if2ibb(i32 noundef %[[A:.*]], i1 noundef %[[B:.*]], i1 noundef %[[C:.*]])
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
 // OGCG:   %[[B_ADDR:.*]] = alloca i8, align 1
diff --git a/clang/test/CIR/CodeGen/lambda-dtor-field.cpp b/clang/test/CIR/CodeGen/lambda-dtor-field.cpp
index e6ef50c57dc140..ccf128d0ce110b 100644
--- a/clang/test/CIR/CodeGen/lambda-dtor-field.cpp
+++ b/clang/test/CIR/CodeGen/lambda-dtor-field.cpp
@@ -215,7 +215,7 @@ void stmt_expr_return(bool cond) {
 // CIR:           cir.yield
 // CIR:         }
 
-// LLVM-LABEL: define dso_local void @_Z16stmt_expr_returnb(i1 noundef zeroext %{{[^,)]+}}) {{.*}} personality ptr @__gxx_personality_v0 {
+// LLVM-LABEL: define dso_local void @_Z16stmt_expr_returnb(i1 noundef %{{[^,)]+}}) {{.*}} personality ptr @__gxx_personality_v0 {
 // LLVM:   %[[LAM5:.*]] = alloca %[[LAM_TY_5:[^,]*]]
 // LLVM:   %[[ACTIVE_ALLOCA:.*]] = alloca i8
 // LLVM:   %[[FA5:.*]] = getelementptr inbounds nuw %[[LAM_TY_5]], ptr %[[LAM5]], i32 0, i32 0
@@ -268,7 +268,7 @@ void stmt_expr_return(bool cond) {
 // LLVM:   call void @_ZN1SD1Ev(ptr {{.*}} %[[FA5_D]])
 // LLVM:   ret void
 
-// OGCG-LABEL: define dso_local void @_Z16stmt_expr_returnb(i1 noundef zeroext %cond){{.*}} personality ptr @__gxx_personality_v0
+// OGCG-LABEL: define dso_local void @_Z16stmt_expr_returnb(i1 noundef %cond){{.*}} personality ptr @__gxx_personality_v0
 // OGCG:   %[[LAM5:.*]] = alloca %[[LAM_TY_5:.*]], align 4
 // OGCG:   %[[FA5:.*]] = getelementptr inbounds nuw %[[LAM_TY_5]], ptr %[[LAM5]], i32 0, i32 0
 // OGCG:   call void @_ZN1SC1Ei(ptr {{.*}} %[[FA5]], i32 {{.*}} 0)
diff --git a/clang/test/CIR/CodeGen/local-static-temp-dtor.cpp b/clang/test/CIR/CodeGen/local-static-temp-dtor.cpp
index a459aa8773033b..5b1b0ff0c66c66 100644
--- a/clang/test/CIR/CodeGen/local-static-temp-dtor.cpp
+++ b/clang/test/CIR/CodeGen/local-static-temp-dtor.cpp
@@ -265,7 +265,7 @@ void cond(bool c) {
 // CIR-BEFORE:           })
 
 // Only the arm that builds the temporary registers its destruction.
-// LLVM-LABEL: define dso_local void @_Z4condb(i1 noundef zeroext %{{.+}})
+// LLVM-LABEL: define dso_local void @_Z4condb(i1 noundef %{{.+}})
 // LLVM:         call i32 @__cxa_guard_acquire(ptr @_ZGVZ4condbE1r)
 // LLVM:         call void @_ZN10NonTrivialC1Ev(ptr noundef nonnull align 4 dereferenceable(4) @_ZGRZ4condbE1r_)
 // LLVM-NEXT:    call i32 @__cxa_atexit(ptr @_ZN10NonTrivialD1Ev, ptr @_ZGRZ4condbE1r_, ptr @__dso_handle)
diff --git a/clang/test/CIR/CodeGen/new-delete-deactivation.cpp b/clang/test/CIR/CodeGen/new-delete-deactivation.cpp
index 0b94fa22750763..b1d58a2278d8e6 100644
--- a/clang/test/CIR/CodeGen/new-delete-deactivation.cpp
+++ b/clang/test/CIR/CodeGen/new-delete-deactivation.cpp
@@ -121,7 +121,7 @@ A *deact_if(bool cond) {
 // CIR:     }
 // CIR:   }
 
-// LLVM-LABEL: define dso_local ptr @_Z8deact_ifb(i1 zeroext %0) {{.*}} personality ptr @__gxx_personality_v0 {
+// LLVM-LABEL: define dso_local ptr @_Z8deact_ifb(i1 %0) {{.*}} personality ptr @__gxx_personality_v0 {
 // LLVM:   br i1 %{{.*}}, label %[[THEN:.*]], label %[[END:.*]]
 // LLVM: [[THEN]]:
 // LLVM:   %[[PTR:.*]] = call noalias nonnull ptr @_Znwm(i64 1) #[[ATTR_BUILTIN_NEW]]
@@ -141,7 +141,7 @@ A *deact_if(bool cond) {
 // LLVM:   call void @_ZdlPv(ptr %[[PTR]])
 // LLVM: [[END]]:
 
-// OGCG-LABEL: define dso_local ptr @_Z8deact_ifb(i1 zeroext %cond) {{.*}} personality ptr @__gxx_personality_v0 {
+// OGCG-LABEL: define dso_local ptr @_Z8deact_ifb(i1 %cond) {{.*}} personality ptr @__gxx_personality_v0 {
 // OGCG: if.then:
 // OGCG:   %[[PTR:.*]] = call {{.*}} ptr @_Znwm(i64 1) #[[OGCG_ATTR_BUILTIN_NEW]]
 // OGCG:   store i1 true, ptr %[[ACTIVE:.*]]
@@ -176,7 +176,7 @@ A *deact_ternary(bool cond) { return (new A(makeB()), cond) ? nullptr : nullptr;
 // CIR:     }
 // CIR:   }
 
-// LLVM-LABEL: define dso_local ptr @_Z13deact_ternaryb(i1 zeroext %0) {{.*}} personality ptr @__gxx_personality_v0 {
+// LLVM-LABEL: define dso_local ptr @_Z13deact_ternaryb(i1 %0) {{.*}} personality ptr @__gxx_personality_v0 {
 // LLVM:   %[[PTR:.*]] = call noalias nonnull ptr @_Znwm(i64 1) #[[ATTR_BUILTIN_NEW]]
 // LLVM:   store i8 1, ptr %[[ACTIVE:.*]]
 // LLVM:   invoke void @_ZN1AC1Ei(ptr {{.*}} %[[PTR]], i32 {{.*}})
@@ -193,7 +193,7 @@ A *deact_ternary(bool cond) { return (new A(makeB()), cond) ? nullptr : nullptr;
 // LLVM: [[DO_DELETE]]:
 // LLVM:   call void @_ZdlPv(ptr %[[PTR]])
 
-// OGCG-LABEL: define dso_local ptr @_Z13deact_ternaryb(i1 zeroext %cond) {{.*}} personality ptr @__gxx_personality_v0 {
+// OGCG-LABEL: define dso_local ptr @_Z13deact_ternaryb(i1 %cond) {{.*}} personality ptr @__gxx_personality_v0 {
 // OGCG: entry:
 // OGCG:   %[[PTR:.*]] = call {{.*}} ptr @_Znwm(i64 1) #[[OGCG_ATTR_BUILTIN_NEW]]
 // OGCG:   store i1 true, ptr %[[ACTIVE:.*]]
diff --git a/clang/test/CodeGen/X86/integer_argument_passing.c b/clang/test/CodeGen/X86/integer_argument_passing.c
index 0c2c191978c9cf..1379064f6eb02d 100644
--- a/clang/test/CodeGen/X86/integer_argument_passing.c
+++ b/clang/test/CodeGen/X86/integer_argument_passing.c
@@ -1,19 +1,23 @@
-// RUN: %clang_cc1 -O2 -triple -x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -triple -i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -triple -i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple -x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple -i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple -i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple -x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple -i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple -i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple -x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple -i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple -i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// RUN: %clang_cc1 -O2 -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// RUN: %clang_cc1 -O2 -fexperimental-abi-lowering -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -fexperimental-abi-lowering -mextend-small-integers=none -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -fexperimental-abi-lowering -mextend-small-integers=conservative -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
+// RUN: %clang_cc1 -O2 -fexperimental-abi-lowering -mextend-small-integers=assumed -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
 // TODO: enable the belowing tests when 'default' is supported.
-// %clang_cc1 -O2 -mextend-small-integers=default -triple -x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
-// %clang_cc1 -O2 -mextend-small-integers=default -triple -i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
-// %clang_cc1 -O2 -mextend-small-integers=default -triple -i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// %clang_cc1 -O2 -mextend-small-integers=default -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// %clang_cc1 -O2 -mextend-small-integers=default -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// %clang_cc1 -O2 -mextend-small-integers=default -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
 
 
 // CALLEE-EXTEND: define{{.*}} i32 @ZeroExtend(i8 noundef %a, i16 noundef %b)
diff --git a/clang/test/CodeGen/attr-counted-by-base-exprs.c b/clang/test/CodeGen/attr-counted-by-base-exprs.c
index 27913b6fb10515..f0235542bf5164 100644
--- a/clang/test/CodeGen/attr-counted-by-base-exprs.c
+++ b/clang/test/CodeGen/attr-counted-by-base-exprs.c
@@ -360,7 +360,7 @@ int test_index_enum_count(struct e *a, int i) {
 
 // Index types narrower and wider than the count.
 // CHECK-LABEL: define dso_local i32 @test_index_char(
-// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]], i8 noundef signext [[I:%.*]]) local_unnamed_addr #[[ATTR8]] {
+// CHECK-SAME: ptr nofree noundef readonly captures(none) [[A:%.*]], i8 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR8]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[A]], align 4
 // CHECK-NEXT:    [[TMP0:%.*]] = sext i8 [[I]] to i32
diff --git a/clang/test/CodeGen/linux-kernel-struct-union-initializer2.c b/clang/test/CodeGen/linux-kernel-struct-union-initializer2.c
index 44c86d9dcfc07c..8710b80e878cf7 100644
--- a/clang/test/CodeGen/linux-kernel-struct-union-initializer2.c
+++ b/clang/test/CodeGen/linux-kernel-struct-union-initializer2.c
@@ -74,7 +74,7 @@ void test2(long long y) {
 
 // Test non-const initializer for struct with padding and bit fields.
 // CHECK-LABEL: define dso_local void @test3(
-// CHECK-SAME: i8 noundef zeroext [[B:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: i8 noundef [[B:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    [[B_ADDR:%.*]] = alloca i8, align 1
 // CHECK-NEXT:    [[S:%.*]] = alloca [[STRUCT_S2:%.*]], align 4
@@ -147,7 +147,7 @@ void test5(int a, int b) {
 }
 
 // CHECK-LABEL: define dso_local void @test6(
-// CHECK-SAME: i8 noundef signext [[X:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: i8 noundef [[X:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    [[X_ADDR:%.*]] = alloca i8, align 1
 // CHECK-NEXT:    [[S:%.*]] = alloca [[STRUCT_S5:%.*]], align 1
diff --git a/clang/test/CodeGen/mangle-windows.c b/clang/test/CodeGen/mangle-windows.c
index 8ffcdf11833277..7ead021740ad59 100644
--- a/clang/test/CodeGen/mangle-windows.c
+++ b/clang/test/CodeGen/mangle-windows.c
@@ -85,4 +85,4 @@ void __vectorcall v6(char a, char b) {}
 // X64: define dso_local x86_vectorcallcc void @"\01v6@@16"(
 
 void __vectorcall v7(long long a, char b, char c, short d) {}
-// CHECK: define dso_local x86_vectorcallcc void @"\01v7@@20"(i64 noundef %a, i8 inreg noundef signext %b, i8 inreg noundef signext %c, i16 noundef signext %d)
+// CHECK: define dso_local x86_vectorcallcc void @"\01v7@@20"(i64 noundef %a, i8 inreg noundef %b, i8 inreg noundef %c, i16 noundef %d)
diff --git a/clang/test/CodeGen/pointer-arithmetic-align.c b/clang/test/CodeGen/pointer-arithmetic-align.c
index 76d829880c8c8e..d9fea17a958065 100644
--- a/clang/test/CodeGen/pointer-arithmetic-align.c
+++ b/clang/test/CodeGen/pointer-arithmetic-align.c
@@ -65,7 +65,7 @@ void ptrsub_4(struct a *ctx) {
 }
 
 // CHECK-LABEL: define dso_local void @neg_ptradd_var_index(
-// CHECK-SAME: ptr nofree noundef writeonly captures(none) [[CTX:%.*]], i8 noundef zeroext [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-SAME: ptr nofree noundef writeonly captures(none) [[CTX:%.*]], i8 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    [[BLOCK:%.*]] = getelementptr inbounds nuw i8, ptr [[CTX]], i64 8
 // CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i64
diff --git a/clang/test/CodeGen/regcall4.c b/clang/test/CodeGen/regcall4.c
index 610c4bbbca762e..aa065d11a66cb3 100644
--- a/clang/test/CodeGen/regcall4.c
+++ b/clang/test/CodeGen/regcall4.c
@@ -14,9 +14,9 @@ void __attribute__((regcall)) v1b(int a, int b) {}
 // X64: define dso_local x86_regcallcc void @__regcall4__v1b(i32 noundef %a, i32 noundef %b)
 
 void __regcall v2(char a, char b) {}
-// X86: define dso_local x86_regcallcc void @__regcall4__v2(i8 inreg noundef signext %a, i8 inreg noundef signext %b)
+// X86: define dso_local x86_regcallcc void @__regcall4__v2(i8 inreg noundef %a, i8 inreg noundef %b)
 // Win64: define dso_local x86_regcallcc void @__regcall4__v2(i8 noundef %a, i8 noundef %b)
-// Lin64: define dso_local x86_regcallcc void @__regcall4__v2(i8 noundef signext %a, i8 noundef signext %b)
+// Lin64: define dso_local x86_regcallcc void @__regcall4__v2(i8 noundef %a, i8 noundef %b)
 
 struct Small { int x; };
 void __regcall v3(int a, struct Small b, int c) {}
diff --git a/clang/test/CodeGen/transparent-union-type.c b/clang/test/CodeGen/transparent-union-type.c
index bcb86d12d5076b..959ad5a6856039 100644
--- a/clang/test/CodeGen/transparent-union-type.c
+++ b/clang/test/CodeGen/transparent-union-type.c
@@ -1,27 +1,27 @@
 // RUN: %clang_cc1 -triple powerpc64le-linux -O2 -target-cpu pwr7 -emit-llvm \
-// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64
+// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,EXT,CHECK-64
 // RUN: %clang_cc1 -triple powerpc64-linux -O2 -target-cpu pwr7 -emit-llvm \
-// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64
+// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,EXT,CHECK-64
 // RUN: %clang_cc1 -triple powerpc-linux -O2 -target-cpu pwr7 -emit-llvm \
-// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32
+// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,EXT,CHECK-32
 // RUN: %clang_cc1 -triple powerpc64-aix -O2 -target-cpu pwr7 -emit-llvm \
-// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64
+// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,EXT,CHECK-64
 // RUN: %clang_cc1 -triple powerpc-aix -O2 -target-cpu pwr7 -emit-llvm \
-// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32
+// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,EXT,CHECK-32
 // RUN: %clang_cc1 -triple riscv64-linux -O2 -emit-llvm -fshort-enums \
-// RUN:   %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64
+// RUN:   %s -o - | FileCheck %s --check-prefixes=CHECK,EXT,CHECK-64
 // RUN: %clang_cc1 -triple riscv32-linux -O2 -emit-llvm -fshort-enums \
-// RUN:   %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32
+// RUN:   %s -o - | FileCheck %s --check-prefixes=CHECK,EXT,CHECK-32
 // RUN: %clang_cc1 -triple i386-linux -O2 -emit-llvm -fshort-enums \
-// RUN:   %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32
+// RUN:   %s -o - | FileCheck %s --check-prefixes=CHECK,NOEXT,CHECK-32
 // RUN: %clang_cc1 -triple x86_64-linux -O2 -emit-llvm -fshort-enums \
-// RUN:   %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64
+// RUN:   %s -o - | FileCheck %s --check-prefixes=CHECK,NOEXT,CHECK-64
 // RUN: %clang_cc1 -triple armv7-linux -O2 -emit-llvm -fshort-enums \
-// RUN:   %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32
+// RUN:   %s -o - | FileCheck %s --check-prefixes=CHECK,EXT,CHECK-32
 // RUN: %clang_cc1 -triple arm64 -target-abi darwinpcs -O2 -emit-llvm \
-// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64
+// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,EXT,CHECK-64
 // RUN: %clang_cc1 -triple aarch64 -target-abi darwinpcs -O2 -emit-llvm \
-// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64
+// RUN:   -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,EXT,CHECK-64
 
 typedef union tu_c {
   signed char a;
@@ -41,13 +41,15 @@ typedef union tu_l {
 } tu_l_t __attribute__((transparent_union));
 
 // CHECK-LABEL: define{{.*}} void @ftest0(
-// CHECK-SAME: i8 noundef signext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// EXT-SAME: i8 noundef signext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// NOEXT-SAME: i8 noundef [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    ret void
 void ftest0(tu_c_t uc) { }
 
 // CHECK-LABEL: define{{.*}} void @ftest1(
-// CHECK-SAME: i16 noundef signext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// EXT-SAME: i16 noundef signext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// NOEXT-SAME: i16 noundef [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    ret void
 void ftest1(tu_s_t uc) { }
@@ -60,7 +62,8 @@ void ftest1(tu_s_t uc) { }
 void ftest1b(tu_s_t *uc) { }
 
 // CHECK-LABEL: define{{.*}} void @ftest2(
-// CHECK-SAME: i16 noundef zeroext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// EXT-SAME: i16 noundef zeroext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// NOEXT-SAME: i16 noundef [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    ret void
 void ftest2(tu_us_t uc) { }
@@ -82,7 +85,8 @@ typedef union etest {
 } etest_t __attribute__((transparent_union));
 
 // CHECK-LABEL: define{{.*}} void @ftest4(
-// CHECK-SAME: i8 noundef zeroext [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// EXT-SAME: i8 noundef zeroext [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// NOEXT-SAME: i8 noundef [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    ret void
 void ftest4(etest_t a) {}
diff --git a/clang/test/CodeGenCXX/new_hot_cold.cpp b/clang/test/CodeGenCXX/new_hot_cold.cpp
index e8ebba1cceee67..fe76d6ae1971c8 100644
--- a/clang/test/CodeGenCXX/new_hot_cold.cpp
+++ b/clang/test/CodeGenCXX/new_hot_cold.cpp
@@ -53,7 +53,7 @@ void hot_cold_new() {
   new ((__hot_cold_t)0) int;
 }
 
-// CHECK: declare noundef nonnull ptr @_Znwm12__hot_cold_t(i64 noundef, i8 noundef zeroext) [[ATTR_NOBUILTIN:#[^ ]*]]
+// CHECK: declare noundef nonnull ptr @_Znwm12__hot_cold_t(i64 noundef, i8 noundef) [[ATTR_NOBUILTIN:#[^ ]*]]
 
 void hot_cold_new_array() {
   // CHECK: call noalias noundef nonnull ptr @_Znam12__hot_cold_t(i64 noundef 1, i8 noundef zeroext 0) [[ATTR_NO_BUILTIN_CALL:#[^ ]*]]
@@ -62,7 +62,7 @@ void hot_cold_new_array() {
   new ((__hot_cold_t)0) int[1];
 }
 
-// CHECK: declare noundef nonnull ptr @_Znam12__hot_cold_t(i64 noundef, i8 noundef zeroext) [[ATTR_NOBUILTIN:#[^ ]*]]
+// CHECK: declare noundef nonnull ptr @_Znam12__hot_cold_t(i64 noundef, i8 noundef) [[ATTR_NOBUILTIN:#[^ ]*]]
 
 void hot_cold_new_nothrow() {
   // CHECK: call noalias noundef ptr @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 noundef 1, {{.*}} @nothrow, i8 noundef zeroext 0) [[ATTR_NO_BUILTIN_NOTHROW_CALL:#[^ ]*]]
@@ -71,7 +71,7 @@ void hot_cold_new_nothrow() {
   new (nothrow, (__hot_cold_t)0) int;
 }
 
-// CHECK: declare noundef ptr @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 noundef, ptr noundef nonnull align 1 dereferenceable(1), i8 noundef zeroext) [[ATTR_NOBUILTIN_NOTHROW:#[^ ]*]]
+// CHECK: declare noundef ptr @_ZnwmRKSt9nothrow_t12__hot_cold_t(i64 noundef, ptr noundef nonnull align 1 dereferenceable(1), i8 noundef) [[ATTR_NOBUILTIN_NOTHROW:#[^ ]*]]
 
 void hot_cold_new_nothrow_array() {
   // CHECK: call noalias noundef ptr @_ZnamRKSt9nothrow_t12__hot_cold_t(i64 noundef 1, {{.*}} @nothrow, i8 noundef zeroext 0) [[ATTR_NO_BUILTIN_NOTHROW_CALL:#[^ ]*]]
@@ -80,7 +80,7 @@ void hot_cold_new_nothrow_array() {
   new (nothrow, (__hot_cold_t)0) int[1];
 }
 
-// CHECK: declare noundef ptr @_ZnamRKSt9nothrow_t12__hot_cold_t(i64 noundef, ptr noundef nonnull align 1 dereferenceable(1), i8 noundef zeroext) [[ATTR_NOBUILTIN_NOTHROW:#[^ ]*]]
+// CHECK: declare noundef ptr @_ZnamRKSt9nothrow_t12__hot_cold_t(i64 noundef, ptr noundef nonnull align 1 dereferenceable(1), i8 noundef) [[ATTR_NOBUILTIN_NOTHROW:#[^ ]*]]
 
 class alignas(32) alignedstruct {
   int x;
@@ -93,7 +93,7 @@ void hot_cold_new_align() {
   new ((__hot_cold_t)0) alignedstruct;
 }
 
-// CHECK: declare noundef nonnull ptr @_ZnwmSt11align_val_t12__hot_cold_t(i64 noundef, i64 noundef, i8 noundef zeroext) [[ATTR_NOBUILTIN:#[^ ]*]]
+// CHECK: declare noundef nonnull ptr @_ZnwmSt11align_val_t12__hot_cold_t(i64 noundef, i64 noundef, i8 noundef) [[ATTR_NOBUILTIN:#[^ ]*]]
 
 void hot_cold_new_align_array() {
   // CHECK: call noalias noundef nonnull align 32 ptr @_ZnamSt11align_val_t12__hot_cold_t(i64 noundef 1, i64 noundef 32, i8 noundef zeroext 0) [[ATTR_NO_BUILTIN_CALL:#[^ ]*]]
@@ -102,7 +102,7 @@ void hot_cold_new_align_array() {
   new ((__hot_cold_t)0) alignedstruct[1];
 }
 
-// CHECK: declare noundef nonnull ptr @_ZnamSt11align_val_t12__hot_cold_t(i64 noundef, i64 noundef, i8 noundef zeroext) [[ATTR_NOBUILTIN:#[^ ]*]]
+// CHECK: declare noundef nonnull ptr @_ZnamSt11align_val_t12__hot_cold_t(i64 noundef, i64 noundef, i8 noundef) [[ATTR_NOBUILTIN:#[^ ]*]]
 
 void hot_cold_new_align_nothrow() {
   // CHECK: call noalias noundef align 32 ptr @_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 noundef 1, i64 noundef 32, {{.*}} @nothrow, i8 noundef zeroext 0) [[ATTR_NO_BUILTIN_NOTHROW_CALL:#[^ ]*]]
@@ -111,7 +111,7 @@ void hot_cold_new_align_nothrow() {
   new (nothrow, (__hot_cold_t)0) alignedstruct;
 }
 
-// CHECK: declare noundef ptr @_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 noundef, i64 noundef, ptr noundef nonnull align 1 dereferenceable(1), i8 noundef zeroext) [[ATTR_NOBUILTIN_NOTHROW:#[^ ]*]]
+// CHECK: declare noundef ptr @_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 noundef, i64 noundef, ptr noundef nonnull align 1 dereferenceable(1), i8 noundef) [[ATTR_NOBUILTIN_NOTHROW:#[^ ]*]]
 
 void hot_cold_new_align_nothrow_array() {
   // CHECK: call noalias noundef align 32 ptr @_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 noundef 1, i64 noundef 32, {{.*}} @nothrow, i8 noundef zeroext 0) [[ATTR_NO_BUILTIN_NOTHROW_CALL:#[^ ]*]]
@@ -120,7 +120,7 @@ void hot_cold_new_align_nothrow_array() {
   new (nothrow, (__hot_cold_t)0) alignedstruct[1];
 }
 
-// CHECK: declare noundef ptr @_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 noundef, i64 noundef, ptr noundef nonnull align 1 dereferenceable(1), i8 noundef zeroext) [[ATTR_NOBUILTIN_NOTHROW:#[^ ]*]]
+// CHECK: declare noundef ptr @_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t(i64 noundef, i64 noundef, ptr noundef nonnull align 1 dereferenceable(1), i8 noundef) [[ATTR_NOBUILTIN_NOTHROW:#[^ ]*]]
 
 // CHECK-DAG: attributes [[ATTR_NOBUILTIN]] = { nobuiltin allocsize(0) {{.*}} }
 // CHECK-DAG: attributes [[ATTR_NOBUILTIN_NOTHROW]] = { nobuiltin nounwind allocsize(0) {{.*}} }
diff --git a/clang/test/CodeGenCXX/noreturn-init-stmt.cpp b/clang/test/CodeGenCXX/noreturn-init-stmt.cpp
index ab857da9746483..f7e690aeb10f3f 100644
--- a/clang/test/CodeGenCXX/noreturn-init-stmt.cpp
+++ b/clang/test/CodeGenCXX/noreturn-init-stmt.cpp
@@ -9,7 +9,7 @@ bool check(const T &);
 int pick(const T &);
 
 // CHECK-LABEL: define dso_local noundef i32 @_Z4testb(
-// CHECK-SAME: i1 noundef zeroext [[COND:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-SAME: i1 noundef [[COND:%.*]]) #[[ATTR0:[0-9]+]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
 // CHECK-NEXT:    [[COND_ADDR:%.*]] = alloca i8, align 1
@@ -51,7 +51,7 @@ int test(bool cond) {
 }
 
 // CHECK-LABEL: define dso_local noundef i32 @_Z11test_switchb(
-// CHECK-SAME: i1 noundef zeroext [[COND:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: i1 noundef [[COND:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca i32, align 4
 // CHECK-NEXT:    [[COND_ADDR:%.*]] = alloca i8, align 1
diff --git a/llvm/include/llvm/ABI/FunctionInfo.h b/llvm/include/llvm/ABI/FunctionInfo.h
index 9edd588c480018..0a6631fe3466e9 100644
--- a/llvm/include/llvm/ABI/FunctionInfo.h
+++ b/llvm/include/llvm/ABI/FunctionInfo.h
@@ -36,6 +36,9 @@ class ArgInfo {
     /// Valid only for integer argument types. Same as 'direct' but also emit a
     /// zero/sign extension attribute.
     Extend,
+    /// Valid only for integer argument types. Same as 'Extend', but the callee
+    /// does not get to assume that the caller actually did the extension.
+    ConservativeExtend,
     /// Pass the argument indirectly via a hidden pointer with the specified
     /// alignment and address space.
     Indirect,
@@ -129,6 +132,12 @@ class ArgInfo {
     return AI;
   }
 
+  static ArgInfo getConservativeExtend(const Type *T) {
+    ArgInfo AI = getExtend(T);
+    AI.TheKind = ConservativeExtend;
+    return AI;
+  }
+
   /// Realign: the caller couldn't guarantee sufficient alignment - the callee
   /// must copy the argument to a properly aligned temporary before use.
   static ArgInfo getIndirect(Align Align, bool ByVal, unsigned AddrSpace = 0,
@@ -199,10 +208,12 @@ class ArgInfo {
   bool isIndirectAliased() const { return TheKind == IndirectAliased; }
   bool isIgnore() const { return TheKind == Ignore; }
   bool isExtend() const { return TheKind == Extend; }
+  bool isConservativeExtend() const { return TheKind == ConservativeExtend; }
   bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
 
   unsigned getDirectOffset() const {
-    assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+    assert((isDirect() || isExtend() || isConservativeExtend()) &&
+           "Not a direct or extend kind");
     return DirectAttr.Offset;
   }
 
@@ -219,7 +230,8 @@ class ArgInfo {
   }
 
   MaybeAlign getDirectAlign() const {
-    assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+    assert((isDirect() || isExtend() || isConservativeExtend()) &&
+           "Not a direct or extend kind");
     return Alignment;
   }
 
@@ -254,22 +266,23 @@ class ArgInfo {
   }
 
   bool isSignExt() const {
-    assert(isExtend() && "Invalid Kind!");
+    assert((isExtend() || isConservativeExtend()) && "Invalid Kind!");
     return SignExt;
   }
 
   bool isZeroExt() const {
-    assert(isExtend() && "Invalid Kind!");
+    assert((isExtend() || isConservativeExtend()) && "Invalid Kind!");
     return ZeroExt;
   }
 
   bool isNoExt() const {
-    assert(isExtend() && "Invalid Kind!");
+    assert((isExtend() || isConservativeExtend()) && "Invalid Kind!");
     return !SignExt && !ZeroExt;
   }
 
   const Type *getCoerceToType() const {
-    assert((isDirect() || isExtend() || isCoerceAndExpand()) &&
+    assert((isDirect() || isExtend() || isConservativeExtend() ||
+            isCoerceAndExpand()) &&
            "Invalid Kind!");
     return CoercionType;
   }
diff --git a/llvm/include/llvm/ABI/TargetInfo.h b/llvm/include/llvm/ABI/TargetInfo.h
index b4236346b254c7..78d30125297e48 100644
--- a/llvm/include/llvm/ABI/TargetInfo.h
+++ b/llvm/include/llvm/ABI/TargetInfo.h
@@ -47,6 +47,17 @@ struct ABICompatInfo {
   ABICompatInfo() : IsMatrixHA(true) {}
 };
 
+/// How promotable integer arguments are passed on X86
+/// (-mextend-small-integers).
+enum class X86ExtendIntegerArgsKind {
+  /// Pass the argument directly, without extension in the caller.
+  Direct,
+  /// Extend in the caller, but do not assume the extension in the callee.
+  Conservative,
+  /// Extend in the caller and assume the extension in the callee.
+  Assumed,
+};
+
 /// Flags controlling X86-specific ABI compatibility behaviour.
 struct X86ABICompatInfo : ABICompatInfo {
   bool PassInt128VectorsInMem : 1;
@@ -55,11 +66,13 @@ struct X86ABICompatInfo : ABICompatInfo {
   bool HonorsRevision98 : 1;
   bool Clang11Compat : 1;
   bool ClassifyUnnamedBitFields : 1;
+  X86ExtendIntegerArgsKind ExtendIntegerArgs;
 
   X86ABICompatInfo()
       : PassInt128VectorsInMem(true), ReturnCXXRecordGreaterThan128InMem(true),
         ClassifyIntegerMMXAsSSE(true), HonorsRevision98(true),
-        Clang11Compat(true), ClassifyUnnamedBitFields(true) {}
+        Clang11Compat(true), ClassifyUnnamedBitFields(true),
+        ExtendIntegerArgs(X86ExtendIntegerArgsKind::Assumed) {}
 };
 
 class TargetInfo {
diff --git a/llvm/lib/ABI/Targets/X86.cpp b/llvm/lib/ABI/Targets/X86.cpp
index a9707470b97805..a3500eea08b487 100644
--- a/llvm/lib/ABI/Targets/X86.cpp
+++ b/llvm/lib/ABI/Targets/X86.cpp
@@ -650,8 +650,16 @@ X86_64TargetInfo::classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
     // If we have a sign or zero extended integer, make sure to return Extend
     // so that the parameter gets the right LLVM IR attributes.
     if (Hi == NoClass && ResType->isInteger()) {
-      if (Ty->isInteger() && isPromotableInteger(cast<IntegerType>(Ty)))
-        return ArgInfo::getExtend(Ty);
+      if (Ty->isInteger() && isPromotableInteger(cast<IntegerType>(Ty))) {
+        switch (getX86ABICompatInfo().ExtendIntegerArgs) {
+        case X86ExtendIntegerArgsKind::Assumed:
+          return ArgInfo::getExtend(Ty);
+        case X86ExtendIntegerArgsKind::Conservative:
+          return ArgInfo::getConservativeExtend(Ty);
+        case X86ExtendIntegerArgsKind::Direct:
+          break;
+        }
+      }
     }
 
     if (ResType->isInteger() && ResType->getSizeInBits() == 128) {
diff --git a/llvm/unittests/ABI/X86TargetInfoTest.cpp b/llvm/unittests/ABI/X86TargetInfoTest.cpp
index 8f0f6bf47bb18a..9da56f48400a26 100644
--- a/llvm/unittests/ABI/X86TargetInfoTest.cpp
+++ b/llvm/unittests/ABI/X86TargetInfoTest.cpp
@@ -33,6 +33,7 @@ using llvm::abi::TargetInfo;
 using llvm::abi::TypeBuilder;
 using llvm::abi::X86ABICompatInfo;
 using llvm::abi::X86AVXABILevel;
+using llvm::abi::X86ExtendIntegerArgsKind;
 
 class X86TargetInfoTest : public ::testing::Test {
 protected:
@@ -76,10 +77,10 @@ class X86TargetInfoTest : public ::testing::Test {
             RecordFlags::CanPassInRegisters)) {}
 
   std::unique_ptr<TargetInfo>
-  target(X86AVXABILevel AVXLevel = X86AVXABILevel::None) const {
+  target(X86AVXABILevel AVXLevel = X86AVXABILevel::None,
+         const X86ABICompatInfo &Compat = X86ABICompatInfo()) const {
     return createX86_64TargetInfo(const_cast<TypeBuilder &>(TB), AVXLevel,
-                                  /*Has64BitPointers=*/true,
-                                  X86ABICompatInfo());
+                                  /*Has64BitPointers=*/true, Compat);
   }
 
   const ABIType *makeVector(const ABIType *Elt, unsigned NumElements,
@@ -976,4 +977,50 @@ TEST_F(X86TargetInfoTest, IntReturnExtension) {
   expectDirectInteger(classifyRet(StructInt128, FI, TI), 128);
 }
 
+TEST_F(X86TargetInfoTest, IntArgExtension) {
+  auto ClassifyArg = [&](const ABIType *ArgTy, X86ExtendIntegerArgsKind Kind,
+                         std::unique_ptr<FunctionInfo> &FI,
+                         std::unique_ptr<TargetInfo> &TI) -> const ArgInfo & {
+    X86ABICompatInfo Compat;
+    Compat.ExtendIntegerArgs = Kind;
+    TI = target(X86AVXABILevel::None, Compat);
+    FI = FunctionInfo::create(llvm::CallingConv::C, Void, {ArgTy});
+    TI->computeInfo(*FI);
+    return FI->getArgInfo(0).Info;
+  };
+  std::unique_ptr<FunctionInfo> FI;
+  std::unique_ptr<TargetInfo> TI;
+
+  // Assumed: extend in the caller and assume the extension in the callee.
+  expectExtendInteger(
+      ClassifyArg(I8, X86ExtendIntegerArgsKind::Assumed, FI, TI), I8,
+      /*IsSigned=*/true);
+  expectExtendInteger(
+      ClassifyArg(Bool, X86ExtendIntegerArgsKind::Assumed, FI, TI), Bool,
+      /*IsSigned=*/false);
+
+  // Conservative: extend in the caller, but do not assume it in the callee.
+  for (auto [Ty, IsSigned] :
+       {std::pair(I8, true), std::pair(I16, true), std::pair(Bool, false)}) {
+    const ArgInfo &Info =
+        ClassifyArg(Ty, X86ExtendIntegerArgsKind::Conservative, FI, TI);
+    EXPECT_TRUE(Info.isConservativeExtend());
+    EXPECT_EQ(Info.isSignExt(), IsSigned);
+    EXPECT_EQ(Info.isZeroExt(), !IsSigned);
+    EXPECT_EQ(Info.getCoerceToType(), Ty);
+  }
+
+  // Direct: no extension at all.
+  expectDirectInteger(ClassifyArg(I8, X86ExtendIntegerArgsKind::Direct, FI, TI),
+                      8);
+  expectDirectInteger(
+      ClassifyArg(I16, X86ExtendIntegerArgsKind::Direct, FI, TI), 16);
+
+  // int is never extended.
+  for (auto Kind : {X86ExtendIntegerArgsKind::Assumed,
+                    X86ExtendIntegerArgsKind::Conservative,
+                    X86ExtendIntegerArgsKind::Direct})
+    expectDirectInteger(ClassifyArg(I32, Kind, FI, TI), 32);
+}
+
 } // namespace
diff --git a/mlir/include/mlir/ABI/ABIRewriteContext.h b/mlir/include/mlir/ABI/ABIRewriteContext.h
index 555561979c15a8..610250ebc01cf2 100644
--- a/mlir/include/mlir/ABI/ABIRewriteContext.h
+++ b/mlir/include/mlir/ABI/ABIRewriteContext.h
@@ -70,6 +70,11 @@ struct ArgClassification {
   /// For Extend: whether to sign-extend (true) or zero-extend (false).
   bool signExtend = false;
 
+  /// For Extend: whether the extension attribute is only added on call sites.
+  /// The caller performs the extension, but the callee does not get to assume
+  /// that it did.
+  bool extendOnCallSiteOnly = false;
+
   /// For Direct: whether a struct coercion can be flattened into
   /// individual register-width arguments.
   bool canFlatten = true;
@@ -103,8 +108,9 @@ struct ArgClassification {
   bool operator==(const ArgClassification &other) const {
     return kind == other.kind && coercedType == other.coercedType &&
            indirectAlign == other.indirectAlign &&
-           signExtend == other.signExtend && canFlatten == other.canFlatten &&
-           byVal == other.byVal &&
+           signExtend == other.signExtend &&
+           extendOnCallSiteOnly == other.extendOnCallSiteOnly &&
+           canFlatten == other.canFlatten && byVal == other.byVal &&
            indirectAddrSpace == other.indirectAddrSpace &&
            directOffset == other.directOffset &&
            neededIntRegs == other.neededIntRegs &&
@@ -143,11 +149,13 @@ struct ArgClassification {
     return c;
   }
 
-  static ArgClassification getExtend(Type coerced, bool signExt) {
+  static ArgClassification getExtend(Type coerced, bool signExt,
+                                     bool onCallSiteOnly = false) {
     ArgClassification c;
     c.kind = ArgKind::Extend;
     c.coercedType = coerced;
     c.signExtend = signExt;
+    c.extendOnCallSiteOnly = onCallSiteOnly;
     return c;
   }
 };

>From 166a0daa1db34e823a96d3a6ab2fa6e666970212 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Wed, 28 Oct 2026 10:57:15 +0100
Subject: [PATCH 03/11] Fix missing enumeration value warning

---
 clang/lib/CodeGen/Targets/XCore.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/CodeGen/Targets/XCore.cpp b/clang/lib/CodeGen/Targets/XCore.cpp
index f9726ec0a661d4..b0fdad93b55df2 100644
--- a/clang/lib/CodeGen/Targets/XCore.cpp
+++ b/clang/lib/CodeGen/Targets/XCore.cpp
@@ -158,6 +158,7 @@ RValue XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
   case ABIArgInfo::CoerceAndExpand:
   case ABIArgInfo::InAlloca:
   case ABIArgInfo::TargetSpecific:
+  case ABIArgInfo::ConservativeExtend:
     llvm_unreachable("Unsupported ABI kind for va_arg");
   case ABIArgInfo::Ignore:
     Val = Address(llvm::UndefValue::get(ArgPtrTy), ArgTy, TypeAlign);

>From aab6d70221bc3b227fe77613899fb72c86fda24e Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Wed, 28 Oct 2026 11:30:05 +0100
Subject: [PATCH 04/11] Convert to -msmall-int-abi-compat flag

---
 clang/include/clang/Basic/CodeGenOptions.def  |  8 +--
 clang/include/clang/Basic/CodeGenOptions.h    |  9 ++-
 clang/include/clang/CIR/MissingFeatures.h     |  2 +-
 clang/include/clang/Options/Options.td        | 57 +++++++++---------
 clang/lib/CIR/Lowering/CIRPasses.cpp          |  9 +--
 clang/lib/CodeGen/CodeGenModule.cpp           | 26 ++++----
 clang/lib/CodeGen/Targets/X86.cpp             | 35 ++++++-----
 clang/lib/Driver/ToolChains/Clang.cpp         | 10 +---
 .../Transforms/abi-lowering/x86_64-bitint.cir | 16 ++---
 .../abi-lowering/x86_64-empty-class.cir       |  4 +-
 .../abi-lowering/x86_64-indirect-variadic.cir |  2 +-
 .../abi-lowering/x86_64-scalars.cir           | 12 ++--
 .../abi-lowering/x86_64-variadic-call.cir     |  4 +-
 .../CodeGen/X86/integer_argument_passing.c    | 60 +++++++++++--------
 .../CodeGen/X86/x86_32-arguments-darwin.c     |  4 +-
 clang/test/CodeGen/matrix-type-builtins.c     |  4 +-
 clang/test/CodeGen/matrix-type-operators.c    | 12 ++--
 clang/test/CodeGen/ms-inline-asm.c            |  2 +-
 clang/test/CodeGenCXX/virtual-bases.cpp       |  4 +-
 clang/test/CodeGenObjC/property-atomic-bool.m |  4 +-
 llvm/include/llvm/ABI/TargetInfo.h            | 18 +++---
 llvm/lib/ABI/Targets/X86.cpp                  | 10 ++--
 22 files changed, 164 insertions(+), 148 deletions(-)

diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 79fe8e9b6e6f58..ab2bface8ba37f 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -550,10 +550,10 @@ CODEGENOPT(ZOSPPA1Name, 1, 1, Benign)
 /// FIXME: Make DebugOptions its own top-level .def file.
 #include "DebugOptions.def"
 
-/// Whether the function should extend small integer parameters: Direct,
-/// Conservative, Assumed, Default.
-ENUM_CODEGENOPT(ExtendIntegerArgs, ExtendIntegerArgsKind, 2,
-                ExtendIntegerArgsKind::Conservative, Benign)
+/// Which ABIs small integer argument passing on X86 platforms should be
+/// compatible with: SysV, Clang, Both.
+ENUM_CODEGENOPT(SmallIntABICompat, SmallIntABICompatKind, 2,
+                SmallIntABICompatKind::Both, Benign)
 
 #undef CODEGENOPT
 #undef ENUM_CODEGENOPT
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index ce0a65847b1270..a26a3bad8835a8 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -283,11 +283,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
     ForceDisable, // Always disable regardless of the target default.
   };
 
-  enum class ExtendIntegerArgsKind {
-    Direct,       // Force the use of Direct.
-    Conservative, // Force the use of ConservativeExtend.
-    Assumed,      // Force the use of Extend.
-    Default, // Use the default rule for the target, which is Extend for now.
+  enum class SmallIntABICompatKind {
+    SysV,  // Compat with SysV ABI (high bits unspecified).
+    Clang, // Compat with old Clang ABI (high bits zero/sign-extended).
+    Both,  // Compat with both. Extend in caller, don't assume in callee.
   };
 
   /// The code model to use (-mcmodel).
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 89158cdb4df05f..be073255c8c2fd 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -182,7 +182,7 @@ struct MissingFeatures {
   static bool aggValueSlotMayOverlap() { return false; }
   static bool aggValueSlotVolatile() { return false; }
   static bool allocToken() { return false; }
-  static bool extendIntegerArgsOption() { return false; }
+  static bool smallIntABICompatOption() { return false; }
   static bool appleArm64CXXABI() { return false; }
   static bool appleKext() { return false; }
   static bool asmGoto() { return false; }
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 5f778107bc385f..21d4bd1b099b5b 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5798,23 +5798,22 @@ def mzos_hlq_clang_EQ : Joined<["-"], "mzos-hlq-clang=">, MetaVarName<"<ClangHLQ
   HelpText<"High level qualifier for z/OS C++RT side deck datasets">;
 def mzos_hlq_csslib_EQ : Joined<["-"], "mzos-hlq-csslib=">, MetaVarName<"<CsslibHLQ>">,
   HelpText<"High level qualifier for z/OS CSSLIB dataset">;
-def mextend_small_integers_EQ : Joined<["-"], "mextend-small-integers=">,
+def msmall_int_abi_compat_EQ : Joined<["-"], "msmall-int-abi-compat=">,
   Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
-  HelpText<"How to handle the small integer parameter: "
-           "'none' (Pass the small integer parameter directly in caller) | "
-           "'conservative' (Always extend small integer parameter in the caller but do not assume "
-           "in the callee that the caller actually did the extension) | "
-           "'assumed' (Assume the small integer parameter has been extened in the caller) | "
-           "'default' (Use the default rule for the target, this value is not yet supported)">,
-  Values<"none,conservative,assumed,default">,
-  NormalizedValuesScope<"CodeGenOptions::ExtendIntegerArgsKind">,
-  NormalizedValues<["Direct", "Conservative", "Assumed", "Default"]>,
-  MarshallingInfoEnum<CodeGenOpts<"ExtendIntegerArgs">, "Conservative">,
+  HelpText<"ABI compatibility for small integer arguments on X86: "
+           "'sysv' (High bits unspecified) | "
+           "'clang' (High bits zero/sign-extended) | "
+           "'both' (High bits extended in caller, "
+           "extension not assumed in callee)">,
+  Values<"sysv,clang,both">,
+  NormalizedValuesScope<"CodeGenOptions::SmallIntABICompatKind">,
+  NormalizedValues<["SysV", "Clang", "Both"]>,
+  MarshallingInfoEnum<CodeGenOpts<"SmallIntABICompat">, "Both">,
   DocBrief<[{
 Specifies how to handle small integer arguments on i386 and x86_64
-targets that generally follow the System V ABI. The value must be 'none',
-'conservative', 'assumed', or 'default'. The default behavior
-depends on the target and can be explicitly requested with 'default'.
+targets that generally follow the System V ABI, excluding Darwin and
+PlayStation targets. The value must be 'sysv', 'clang', or 'both'.
+The default behavior is 'both'.
 
 In the past, on System V i386 and x86_64 targets, Clang passed promotable
 integer arguments (non-variadic arguments with types smaller than 'int')
@@ -5824,20 +5823,22 @@ convention did not conform to the documented ABI for these targets, which
 does not require the caller to perform this extension. This can introduce
 incompatibilities with code generated by other compilers on these targets.
 
-On most targets using the System V ABI, Clang no longer assumes that
-callers perform this extension. In order to maintain compatibility with
-code compiled by old versions of Clang, Clang will still perform the extension
-in the caller. This is the 'conservative' behavior. If compatibility with old
-Clang code is not required, extension in the caller can be disabled using
-'none', which may have minor performance and code-size benefits.
-
-On certain targets which use Clang as the system compiler, Clang continues
-to perform extension in the caller and assume it in in the callee. This is the
-behavior of 'assumed'. These platforms therefore diverge from the
-standard System V ABI. If compatibility with other compilers which do not
-recognize this divergence is required, 'conservative' may be used.
-Using 'none' on these targets is allowed but may lead to ABI mismatches.
-These targets include Apple and PlayStation platforms.}]>;
+If 'sysv' is used, promotable integer arguments will not be extended by the
+caller. This is conformant with the System V ABI, but may break compatibility
+with old Clang-built objects.
+
+If 'clang' is used, promotable integer arguments are extended by the caller,
+and the callee assumes this extension has happend. This restores the previous
+(before version 24) behavior of Clang, but may be incompatible with other
+compilers like GCC following the System V ABI.
+
+If 'both' is used (the default), promotable integer types will be extended by
+the caller, but the callee will not assume that this extension has happened.
+This is compatible with both the System V ABI, and the old Clang ABI.
+
+The option has no effect on non-X86 targets, and when targeting the Windows,
+Darwin and PlayStation operating systems. Windows never used argument extension
+in the first place, and Darwin/PlayStation follow the Clang ABI.}]>;
 def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group<m_Group>;
 def mno_global_merge : Flag<["-"], "mno-global-merge">, Group<m_Group>,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp
index 7b82978ead0fe3..e42e5d29d1956d 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -68,10 +68,11 @@ getX86ABICompatInfo(const llvm::Triple &triple,
       compat > clang::LangOptions::ClangABI::Ver20 && !triple.isPS();
   abiCompat.Clang11Compat =
       compat <= clang::LangOptions::ClangABI::Ver11 || triple.isPS();
-  // Match the classic CodeGen default of -mextend-small-integers.
-  assert(!cir::MissingFeatures::extendIntegerArgsOption());
-  abiCompat.ExtendIntegerArgs =
-      llvm::abi::X86ExtendIntegerArgsKind::Conservative;
+  // Match the classic CodeGen default of -msmall-int-abi-compat.
+  assert(!cir::MissingFeatures::smallIntABICompatOption());
+  abiCompat.SmallIntABICompat = triple.isOSDarwin() || triple.isPS()
+                                    ? llvm::abi::SmallIntABICompatKind::Clang
+                                    : llvm::abi::SmallIntABICompatKind::Both;
   return abiCompat;
 }
 
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index f609a54f789ba0..beec300304d0bd 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -407,18 +407,20 @@ static void initializeX86ABICompatInfo(llvm::abi::X86ABICompatInfo &CompatInfo,
   CompatInfo.Clang11Compat = Compat <= LangOptions::ClangABI::Ver11 || T.isPS();
   CompatInfo.ClassifyUnnamedBitFields =
       Compat > LangOptions::ClangABI::Ver23 && !T.isPS();
-  switch (CGOpts.getExtendIntegerArgs()) {
-  case CodeGenOptions::ExtendIntegerArgsKind::Assumed:
-    CompatInfo.ExtendIntegerArgs = llvm::abi::X86ExtendIntegerArgsKind::Assumed;
-    break;
-  case CodeGenOptions::ExtendIntegerArgsKind::Conservative:
-    CompatInfo.ExtendIntegerArgs =
-        llvm::abi::X86ExtendIntegerArgsKind::Conservative;
-    break;
-  case CodeGenOptions::ExtendIntegerArgsKind::Direct:
-  case CodeGenOptions::ExtendIntegerArgsKind::Default:
-    CompatInfo.ExtendIntegerArgs = llvm::abi::X86ExtendIntegerArgsKind::Direct;
-    break;
+  if (T.isOSDarwin() || T.isPS()) {
+    CompatInfo.SmallIntABICompat = llvm::abi::SmallIntABICompatKind::Clang;
+  } else {
+    switch (CGOpts.getSmallIntABICompat()) {
+    case CodeGenOptions::SmallIntABICompatKind::SysV:
+      CompatInfo.SmallIntABICompat = llvm::abi::SmallIntABICompatKind::SysV;
+      break;
+    case CodeGenOptions::SmallIntABICompatKind::Clang:
+      CompatInfo.SmallIntABICompat = llvm::abi::SmallIntABICompatKind::Clang;
+      break;
+    case CodeGenOptions::SmallIntABICompatKind::Both:
+      CompatInfo.SmallIntABICompat = llvm::abi::SmallIntABICompatKind::Both;
+      break;
+    }
   }
 }
 
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index bab1655820f5bf..55cec7c8bb66db 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -471,6 +471,14 @@ static bool shouldExtendReturnType(const ABIInfo &Info, QualType RetTy) {
   return Info.isPromotableIntegerTypeForABI(RetTy);
 }
 
+static CodeGenOptions::SmallIntABICompatKind
+getEffectiveSmallIntABICompat(const CodeGenOptions &Opts,
+                              const llvm::Triple &T) {
+  if (T.isOSDarwin() || T.isPS())
+    return CodeGenOptions::SmallIntABICompatKind::Clang;
+  return Opts.getSmallIntABICompat();
+}
+
 ABIArgInfo X86_32ABIInfo::getIndirectReturnResult(QualType RetTy, CCState &State) const {
   // If the return value is indirect, then the hidden argument is consuming one
   // integer register.
@@ -993,18 +1001,17 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State,
   bool InReg = shouldPrimitiveUseInReg(Ty, State);
 
   if (isPromotableIntegerTypeForABI(Ty)) {
-    switch (getCodeGenOpts().getExtendIntegerArgs()) {
-    case CodeGenOptions::ExtendIntegerArgsKind::Assumed:
+    switch (getEffectiveSmallIntABICompat(getCodeGenOpts(),
+                                          getTarget().getTriple())) {
+    case CodeGenOptions::SmallIntABICompatKind::SysV:
+      break;
+    case CodeGenOptions::SmallIntABICompatKind::Clang:
       return InReg ? ABIArgInfo::getExtendInReg(Ty, CGT.ConvertType(Ty))
                    : ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));
-    case CodeGenOptions::ExtendIntegerArgsKind::Conservative:
-      return InReg
-                 ? ABIArgInfo::getConservativeExtendInReg(Ty, CGT.ConvertType(Ty))
-                 : ABIArgInfo::getConservativeExtend(Ty, CGT.ConvertType(Ty));
-    case CodeGenOptions::ExtendIntegerArgsKind::Direct:
-    case CodeGenOptions::ExtendIntegerArgsKind::Default:
-      // ExtendIntegerArgsKind::Direct will be handled at the last.
-      break;
+    case CodeGenOptions::SmallIntABICompatKind::Both:
+      return InReg ? ABIArgInfo::getConservativeExtendInReg(Ty,
+                                                            CGT.ConvertType(Ty))
+                   : ABIArgInfo::getConservativeExtend(Ty, CGT.ConvertType(Ty));
     }
   }
 
@@ -3007,13 +3014,13 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs,
       // Treat an enum type as its underlying type.
       if (const auto *ED = Ty->getAsEnumDecl())
         Ty = ED->getIntegerType();
-      auto Kind = getCodeGenOpts().getExtendIntegerArgs();
+      auto Kind = getEffectiveSmallIntABICompat(getCodeGenOpts(),
+                                                getTarget().getTriple());
       if (Ty->isIntegralOrEnumerationType() &&
           isPromotableIntegerTypeForABI(Ty)) {
-      // ExtendIntegerArgsKind::Direct will be handled at the last.
-      if (Kind == CodeGenOptions::ExtendIntegerArgsKind::Conservative)
+      if (Kind == CodeGenOptions::SmallIntABICompatKind::Both)
         return ABIArgInfo::getConservativeExtend(Ty, CGT.ConvertType(Ty));
-      else if (Kind == CodeGenOptions::ExtendIntegerArgsKind::Assumed)
+      else if (Kind == CodeGenOptions::SmallIntABICompatKind::Clang)
         return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));
       }
     }
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index a8f12dd7a21561..84820faf700248 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7461,14 +7461,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.addOptOutFlag(CmdArgs, options::OPT_mstack_arg_probe,
                      options::OPT_mno_stack_arg_probe);
 
-  // TODO: Support 'default' for OPT_mextend_small_integers_EQ
-  if (Arg *A = Args.getLastArg(options::OPT_mextend_small_integers_EQ)) {
-    if (StringRef(A->getValue()) == "default")
-      D.Diag(diag::err_drv_unsupported_option_argument)
-          << A->getSpelling() << A->getValue();
-    else
-      A->render(Args, CmdArgs);
-  }
+  if (Arg *A = Args.getLastArg(options::OPT_msmall_int_abi_compat_EQ))
+    A->render(Args, CmdArgs);
 
   if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
                                options::OPT_mno_restrict_it)) {
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir
index 5aa1b0b28ad319..4fd62178523130 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-bitint.cir
@@ -43,12 +43,12 @@ module attributes {
   }
 
   // CHECK-LABEL: cir.func{{.*}} @ret_b17(
-  // CHECK-SAME:    %arg0: !cir.int<s, 17, bitint> {llvm.signext})
+  // CHECK-SAME:    %arg0: !cir.int<s, 17, bitint>)
   // CHECK-SAME:    -> !cir.int<s, 17, bitint>
   // CHECK-NEXT:    cir.return %arg0 : !cir.int<s, 17, bitint>
 
   // LLVM-LABEL: define i17 @ret_b17(
-  // LLVM-SAME:    i17 signext %[[ARG:[0-9]+]])
+  // LLVM-SAME:    i17 %[[ARG:[0-9]+]])
   // LLVM-NEXT:    ret i17 %[[ARG]]
 
   // Unsigned takes zeroext instead.
@@ -57,12 +57,12 @@ module attributes {
   }
 
   // CHECK-LABEL: cir.func{{.*}} @ret_ub17(
-  // CHECK-SAME:    %arg0: !cir.int<u, 17, bitint> {llvm.zeroext})
+  // CHECK-SAME:    %arg0: !cir.int<u, 17, bitint>)
   // CHECK-SAME:    -> !cir.int<u, 17, bitint>
   // CHECK-NEXT:    cir.return %arg0 : !cir.int<u, 17, bitint>
 
   // LLVM-LABEL: define i17 @ret_ub17(
-  // LLVM-SAME:    i17 zeroext %[[ARG:[0-9]+]])
+  // LLVM-SAME:    i17 %[[ARG:[0-9]+]])
   // LLVM-NEXT:    ret i17 %[[ARG]]
 
   // Already the width the classifier names: Direct, nothing to rewrite.
@@ -365,7 +365,7 @@ module attributes {
   }
 
   // CHECK-LABEL: cir.func{{.*}} @take_widths(
-  // CHECK-SAME:    %arg0: !cir.int<s, 17, bitint> {llvm.signext}
+  // CHECK-SAME:    %arg0: !cir.int<s, 17, bitint>
   // CHECK-SAME:    , %arg1: !u64i, %arg2: !u64i, %arg3: !u64i)
   // CHECK-NEXT:    %[[W33SLOT:[0-9]+]] = cir.alloca "coerce" align(8) : !cir.ptr<!u64i>
   // CHECK-NEXT:    cir.store %arg3, %[[W33SLOT]] : !u64i, !cir.ptr<!u64i>
@@ -388,7 +388,7 @@ module attributes {
   // CHECK-NEXT:    cir.return
 
   // LLVM-LABEL: define void @take_widths(
-  // LLVM-SAME:    i17 signext %{{[0-9]+}}, i64 %[[A1:[0-9]+]]
+  // LLVM-SAME:    i17 %{{[0-9]+}}, i64 %[[A1:[0-9]+]]
   // LLVM-SAME:    , i64 %[[A2:[0-9]+]], i64 %[[A3:[0-9]+]])
   // The fourth register holds the 33-bit value, materialized first.
   // LLVM-NEXT:    %[[W33SLOT:[0-9]+]] = alloca i64, align 8
@@ -416,7 +416,7 @@ module attributes {
   }
 
   // CHECK-LABEL: cir.func{{.*}} @call_widths(
-  // CHECK-SAME:    %arg0: !cir.int<s, 17, bitint> {llvm.signext}
+  // CHECK-SAME:    %arg0: !cir.int<s, 17, bitint>
   // CHECK-SAME:    , %arg1: !u64i, %arg2: !u64i, %arg3: !u64i)
   // CHECK-NEXT:    %[[V33SLOT:[0-9]+]] = cir.alloca "coerce" align(8) : !cir.ptr<!u64i>
   // CHECK-NEXT:    cir.store %arg3, %[[V33SLOT]] : !u64i, !cir.ptr<!u64i>
@@ -460,7 +460,7 @@ module attributes {
   // CHECK-NEXT:    cir.return
 
   // LLVM-LABEL: define void @call_widths(
-  // LLVM-SAME:    i17 signext %[[A0:[0-9]+]], i64 %[[A1:[0-9]+]]
+  // LLVM-SAME:    i17 %[[A0:[0-9]+]], i64 %[[A1:[0-9]+]]
   // LLVM-SAME:    , i64 %[[A2:[0-9]+]], i64 %[[A3:[0-9]+]])
   // LLVM-NEXT:    %[[V33SLOT:[0-9]+]] = alloca i64, align 8
   // LLVM-NEXT:    store i64 %[[A3]], ptr %[[V33SLOT]], align 8
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir
index 8b4ef992a1a086..f3f02a89b6b099 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-empty-class.cir
@@ -123,8 +123,8 @@ module attributes {
     cir.return %arg0 : !s32i
   }
 
-  // CHECK: cir.func{{.*}} @take_middle(%arg0: !s32i, %arg1: !u8i {llvm.zeroext}) -> !s32i
-  // LLVM: define i32 @take_middle(i32 %{{.*}}, i8 zeroext %{{.*}})
+  // CHECK: cir.func{{.*}} @take_middle(%arg0: !s32i, %arg1: !u8i) -> !s32i
+  // LLVM: define i32 @take_middle(i32 %{{.*}}, i8 %{{.*}})
 
   // A byte-sized record needing no padding is data: the padded flag is the
   // boundary, not the size.
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-indirect-variadic.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-indirect-variadic.cir
index 80a8f74f2df1ad..ea73947b49ee7a 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-indirect-variadic.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-indirect-variadic.cir
@@ -84,7 +84,7 @@ module attributes {
     cir.return
   }
 
-  // CHECK-LABEL: cir.func {{.*}}@indirect_narrow(%arg0: !cir.ptr<!cir.func<(!cir.ptr<!s8i>, ...) -> !s32i>>, %arg1: !cir.ptr<!s8i>, %arg2: !s8i {llvm.signext})
+  // CHECK-LABEL: cir.func {{.*}}@indirect_narrow(%arg0: !cir.ptr<!cir.func<(!cir.ptr<!s8i>, ...) -> !s32i>>, %arg1: !cir.ptr<!s8i>, %arg2: !s8i)
   // CHECK-NOT: cir.cast bitcast %arg0
   // CHECK:   %{{.+}} = cir.call %arg0(%arg1, %arg2) : (!cir.ptr<!cir.func<(!cir.ptr<!s8i>, ...) -> !s32i>>, !cir.ptr<!s8i>, !s8i {llvm.signext}) -> !s32i
 
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-scalars.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-scalars.cir
index 515507ef6aa7f2..815e50bc6c1fe8 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-scalars.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-scalars.cir
@@ -47,21 +47,21 @@ module attributes {
     cir.return
   }
 
-  // CHECK: cir.func{{.*}} @take_s8(%arg0: !s8i {llvm.signext})
+  // CHECK: cir.func{{.*}} @take_s8(%arg0: !s8i)
 
   // Unsigned sub-register integer is zero-extended.
   cir.func @take_u16(%arg0: !u16i) {
     cir.return
   }
 
-  // CHECK: cir.func{{.*}} @take_u16(%arg0: !u16i {llvm.zeroext})
+  // CHECK: cir.func{{.*}} @take_u16(%arg0: !u16i)
 
   // bool is zero-extended.
   cir.func @take_bool(%arg0: !cir.bool) {
     cir.return
   }
 
-  // CHECK: cir.func{{.*}} @take_bool(%arg0: !cir.bool {llvm.zeroext})
+  // CHECK: cir.func{{.*}} @take_bool(%arg0: !cir.bool)
 
   // Call site picks up the same extension attribute on the operand.
   cir.func @call_s8(%arg0: !s8i) {
@@ -110,9 +110,9 @@ module attributes {
   // CHECK: cir.call @ret_i128(%arg0) : (!s128i) -> !s128i
 }
 
-// LLVM: define void @take_s8(i8 signext %{{.+}})
-// LLVM: define void @take_u16(i16 zeroext %{{.+}})
-// LLVM: define void @take_bool(i1 zeroext %{{.+}})
+// LLVM: define void @take_s8(i8 %{{.+}})
+// LLVM: define void @take_u16(i16 %{{.+}})
+// LLVM: define void @take_bool(i1 %{{.+}})
 // LLVM: define i8 @ret_s8()
 // LLVM: define i16 @ret_u16()
 // LLVM: define i128 @ret_i128(i128 %{{.+}})
diff --git a/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir b/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir
index dc3130d5e5d660..49115005eafa37 100644
--- a/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir
+++ b/clang/test/CIR/Transforms/abi-lowering/x86_64-variadic-call.cir
@@ -55,7 +55,7 @@ module attributes {
     cir.return
   }
 
-  // CHECK: cir.func{{.*}} @pass_narrow(%arg0: !cir.ptr<!s8i>, %arg1: !s8i {llvm.signext})
+  // CHECK: cir.func{{.*}} @pass_narrow(%arg0: !cir.ptr<!s8i>, %arg1: !s8i)
   // CHECK:   cir.call @variadic(%arg0, %arg1) : (!cir.ptr<!s8i>, !s8i {llvm.signext}) -> !s32i
 
   cir.func @pass_double(%arg0: !cir.ptr<!s8i>, %arg1: !cir.double) {
@@ -199,7 +199,7 @@ module attributes {
 // LLVM: define void @pass_scalar(ptr %{{[^,)]+}}, i32 %{{[^,)]+}})
 // LLVM:   call i32 (ptr, ...) @variadic(ptr %{{[^,)]+}}, i32 %{{[^,)]+}})
 
-// LLVM: define void @pass_narrow(ptr %{{[^,)]+}}, i8 signext %{{[^,)]+}})
+// LLVM: define void @pass_narrow(ptr %{{[^,)]+}}, i8 %{{[^,)]+}})
 // LLVM:   call i32 (ptr, ...) @variadic(ptr %{{[^,)]+}}, i8 signext %{{[^,)]+}})
 
 // LLVM: define void @pass_double(ptr %{{[^,)]+}}, double %{{[^,)]+}})
diff --git a/clang/test/CodeGen/X86/integer_argument_passing.c b/clang/test/CodeGen/X86/integer_argument_passing.c
index 1379064f6eb02d..12b06a85d49762 100644
--- a/clang/test/CodeGen/X86/integer_argument_passing.c
+++ b/clang/test/CodeGen/X86/integer_argument_passing.c
@@ -1,33 +1,45 @@
-// RUN: %clang_cc1 -O2 -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=none -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=conservative -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
-// RUN: %clang_cc1 -O2 -mextend-small-integers=assumed -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
-// RUN: %clang_cc1 -O2 -fexperimental-abi-lowering -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -fexperimental-abi-lowering -mextend-small-integers=none -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -fexperimental-abi-lowering -mextend-small-integers=conservative -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-EXTEND
-// RUN: %clang_cc1 -O2 -fexperimental-abi-lowering -mextend-small-integers=assumed -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
-// TODO: enable the belowing tests when 'default' is supported.
-// %clang_cc1 -O2 -mextend-small-integers=default -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
-// %clang_cc1 -O2 -mextend-small-integers=default -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
-// %clang_cc1 -O2 -mextend-small-integers=default -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-EXTEND
+// Test platform defaults.
+// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple i386-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-sie-ps5 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-pc-windows-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+//
+// Same with ABI lowering library.
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple i386-linux-gnu -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple i386-pc-win32 -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-sie-ps5 -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-pc-windows-gnu -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-NO-ASSUME-EXTENDED
 
+// Test -msmall-int-abi-compat flag
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=both %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=sysv %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=clang %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=both -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=sysv -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=clang -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+//
+// Check that the flag has no effect on targets with different platform ABI.
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=both %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=sysv %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=clang %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=both -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=sysv -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=clang -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
 
-// CALLEE-EXTEND: define{{.*}} i32 @ZeroExtend(i8 noundef %a, i16 noundef %b)
-// CALLEE-NO-EXTEND: define{{.*}} i32 @ZeroExtend(i8 noundef zeroext %a, i16 noundef zeroext %b)
+// CALLEE-ASSUME-EXTENDED: define{{.*}} i32 @ZeroExtend(i8 noundef zeroext %a, i16 noundef zeroext %b)
+// CALLEE-NO-ASSUME-EXTENDED: define{{.*}} i32 @ZeroExtend(i8 noundef %a, i16 noundef %b)
 unsigned ZeroExtend(unsigned char a, unsigned short b) {
   return a*b;
 }
 
-// CALLEE-EXTEND: define{{.*}} i32 @SignExtend(i8 noundef %a, i16 noundef %b)
-// CALLEE-NO-EXTEND: define{{.*}} i32 @SignExtend(i8 noundef signext %a, i16 noundef signext %b)
+// CALLEE-ASSUME-EXTENDED: define{{.*}} i32 @SignExtend(i8 noundef signext %a, i16 noundef signext %b)
+// CALLEE-NO-ASSUME-EXTENDED: define{{.*}} i32 @SignExtend(i8 noundef %a, i16 noundef %b)
 int SignExtend(char a, short b) {
   return a*b;
 }
diff --git a/clang/test/CodeGen/X86/x86_32-arguments-darwin.c b/clang/test/CodeGen/X86/x86_32-arguments-darwin.c
index a44981769b28e8..8eeba631157d07 100644
--- a/clang/test/CodeGen/X86/x86_32-arguments-darwin.c
+++ b/clang/test/CodeGen/X86/x86_32-arguments-darwin.c
@@ -30,7 +30,7 @@ long double f5(void) {
   return 0;
 }
 
-// CHECK-LABEL: define{{.*}} void @f6(i8 noundef %a0, i16 noundef %a1, i32 noundef %a2, i64 noundef %a3, ptr noundef %a4)
+// CHECK-LABEL: define{{.*}} void @f6(i8 noundef signext %a0, i16 noundef signext %a1, i32 noundef %a2, i64 noundef %a3, ptr noundef %a4)
 void f6(char a0, short a1, int a2, long long a3, void *a4) {}
 
 // CHECK-LABEL: define{{.*}} void @f7(i32 noundef %a0)
@@ -226,7 +226,7 @@ typedef int v4i32 __attribute__((__vector_size__(16)));
 v4i32 f55(v4i32 arg) { return arg+arg; }
 
 // CHECK-LABEL: define{{.*}} void @f56(
-// CHECK: i8 noundef %a0, ptr noundef byval(%struct.s56_0) align 4 %a1,
+// CHECK: i8 noundef signext %a0, ptr noundef byval(%struct.s56_0) align 4 %a1,
 // CHECK: i64 noundef %a2.coerce, ptr noundef byval(%struct.s56_1) align 4 %0,
 // CHECK: i64 noundef %a4.coerce, ptr noundef byval(%struct.s56_2) align 4 %1,
 // CHECK: <4 x i32> noundef %a6, ptr noundef byval(%struct.s56_3) align 16 %a7,
diff --git a/clang/test/CodeGen/matrix-type-builtins.c b/clang/test/CodeGen/matrix-type-builtins.c
index 5517c8bdc3276a..f6e67d5933ee4f 100644
--- a/clang/test/CodeGen/matrix-type-builtins.c
+++ b/clang/test/CodeGen/matrix-type-builtins.c
@@ -154,7 +154,7 @@ void column_major_load_with_stride_math_int(int *Ptr, int S) {
 }
 
 void column_major_load_with_stride_math_s_int(int *Ptr, short S) {
-  // COMMON-LABEL:  define{{.*}} void @column_major_load_with_stride_math_s_int(ptr %Ptr, i16 %S)
+  // COMMON-LABEL:  define{{.*}} void @column_major_load_with_stride_math_s_int(ptr %Ptr, i16 signext %S)
   // COMMON:         [[S:%.*]] = load i16, ptr %S.addr, align 2
   // COMMON-NEXT:    [[S_EXT:%.*]] = sext i16 [[S]] to i32
   // COMMON-NEXT:    [[STRIDE:%.*]] = add nsw i32 [[S_EXT]], 32
@@ -261,7 +261,7 @@ void column_major_store_with_stride_math_int(int *Ptr, int S) {
 }
 
 void column_major_store_with_stride_math_s_int(int *Ptr, short S) {
-  // COMMON-LABEL: define{{.*}} void @column_major_store_with_stride_math_s_int(ptr %Ptr, i16 %S)
+  // COMMON-LABEL: define{{.*}} void @column_major_store_with_stride_math_s_int(ptr %Ptr, i16 signext %S)
   // COMMON:         [[M:%.*]] = load <80 x i32>, ptr {{.*}}, align 4
   // CHECK32-NEXT:   [[PTR:%.*]] = load ptr, ptr %Ptr.addr, align 4
   // CHECK64-NEXT:   [[PTR:%.*]] = load ptr, ptr %Ptr.addr, align 8
diff --git a/clang/test/CodeGen/matrix-type-operators.c b/clang/test/CodeGen/matrix-type-operators.c
index 8cef8cf75c115c..dde9857921cd12 100644
--- a/clang/test/CodeGen/matrix-type-operators.c
+++ b/clang/test/CodeGen/matrix-type-operators.c
@@ -321,7 +321,7 @@ void subtract_compound_matrix_matrix_unsigned_long_long(ullx4x2_t a, ullx4x2_t b
 }
 
 void add_matrix_scalar_int_short(ix9x3_t a, short vs) {
-  // CHECK-LABEL: define{{.*}} void @add_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef %vs)
+  // CHECK-LABEL: define{{.*}} void @add_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef signext %vs)
   // NOOPT:        [[MATRIX:%.*]] = load <27 x i32>, ptr [[MAT_ADDR:%.*]], align 4{{$}}
   // NOOPT-NEXT:   [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:          [[MATRIX:%.*]] = load <27 x i32>, ptr [[MAT_ADDR:%.*]], align 4, !tbaa !{{[0-9]+}}{{$}}
@@ -336,7 +336,7 @@ void add_matrix_scalar_int_short(ix9x3_t a, short vs) {
 }
 
 void add_compound_matrix_scalar_int_short(ix9x3_t a, short vs) {
-  // CHECK-LABEL: define{{.*}} void @add_compound_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef %vs)
+  // CHECK-LABEL: define{{.*}} void @add_compound_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef signext %vs)
   // NOOPT:       [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:         [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2, !tbaa !{{[0-9]+}}{{$}}
   // CHECK-NEXT:  [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i32
@@ -351,7 +351,7 @@ void add_compound_matrix_scalar_int_short(ix9x3_t a, short vs) {
 }
 
 void subtract_compound_matrix_scalar_int_short(ix9x3_t a, short vs) {
-  // CHECK-LABEL: define{{.*}} void @subtract_compound_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef %vs)
+  // CHECK-LABEL: define{{.*}} void @subtract_compound_matrix_scalar_int_short(<27 x i32> noundef %a, i16 noundef signext %vs)
   // NOOPT:       [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:         [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2, !tbaa !{{[0-9]+}}{{$}}
   // CHECK-NEXT:  [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i32
@@ -456,7 +456,7 @@ void subtract_compound_matrix_scalar_int_unsigned_long_long(ix9x3_t a, unsigned
 }
 
 void add_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
-  // CHECK-LABEL: define{{.*}} void @add_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef %vs)
+  // CHECK-LABEL: define{{.*}} void @add_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef signext %vs)
   // NOOPT:         [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:           [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2, !tbaa !{{[0-9]+}}{{$}}
   // CHECK-NEXT:    [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i64
@@ -471,7 +471,7 @@ void add_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
 }
 
 void add_compound_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
-  // CHECK-LABEL: define{{.*}} void @add_compound_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef %vs)
+  // CHECK-LABEL: define{{.*}} void @add_compound_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef signext %vs)
   // NOOPT:       [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:         [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2, !tbaa !{{[0-9]+}}{{$}}
   // CHECK-NEXT:  [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i64
@@ -486,7 +486,7 @@ void add_compound_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
 }
 
 void subtract_compound_matrix_scalar_long_long_int_short(ullx4x2_t b, short vs) {
-  // CHECK-LABEL: define{{.*}} void @subtract_compound_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef %vs)
+  // CHECK-LABEL: define{{.*}} void @subtract_compound_matrix_scalar_long_long_int_short(<8 x i64> noundef %b, i16 noundef signext %vs)
   // NOOPT:       [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2{{$}}
   // OPT:         [[SCALAR:%.*]] = load i16, ptr %vs.addr, align 2, !tbaa !{{[0-9]+}}{{$}}
   // CHECK-NEXT:  [[SCALAR_EXT:%.*]] = sext i16 [[SCALAR]] to i64
diff --git a/clang/test/CodeGen/ms-inline-asm.c b/clang/test/CodeGen/ms-inline-asm.c
index 714167b724590e..c3eef9a23e1661 100644
--- a/clang/test/CodeGen/ms-inline-asm.c
+++ b/clang/test/CodeGen/ms-inline-asm.c
@@ -581,7 +581,7 @@ void t40(float a) {
 }
 
 void t41(unsigned short a) {
-// CHECK-LABEL: define{{.*}} void @t41(i16 noundef %a)
+// CHECK-LABEL: define{{.*}} void @t41(i16 noundef zeroext %a)
   __asm mov cs, a;
 // CHECK: mov cs, $0
   __asm mov ds, a;
diff --git a/clang/test/CodeGenCXX/virtual-bases.cpp b/clang/test/CodeGenCXX/virtual-bases.cpp
index fcb6a360091537..325e67b4e72882 100644
--- a/clang/test/CodeGenCXX/virtual-bases.cpp
+++ b/clang/test/CodeGenCXX/virtual-bases.cpp
@@ -20,8 +20,8 @@ struct C : virtual A {
   C(bool);
 };
 
-// CHECK-LABEL: define{{.*}} void @_ZN1CC2Eb(ptr {{[^,]*}} %this, ptr noundef %vtt, i1 noundef %0) unnamed_addr
-// CHECK-LABEL: define{{.*}} void @_ZN1CC1Eb(ptr {{[^,]*}} %this, i1 noundef %0) unnamed_addr
+// CHECK-LABEL: define{{.*}} void @_ZN1CC2Eb(ptr {{[^,]*}} %this, ptr noundef %vtt, i1 noundef zeroext %0) unnamed_addr
+// CHECK-LABEL: define{{.*}} void @_ZN1CC1Eb(ptr {{[^,]*}} %this, i1 noundef zeroext %0) unnamed_addr
 C::C(bool) { }
 
 // PR6251
diff --git a/clang/test/CodeGenObjC/property-atomic-bool.m b/clang/test/CodeGenObjC/property-atomic-bool.m
index 1afefab0a89adf..aac5295999b254 100644
--- a/clang/test/CodeGenObjC/property-atomic-bool.m
+++ b/clang/test/CodeGenObjC/property-atomic-bool.m
@@ -5,7 +5,7 @@
 // CHECK:   %[[TOBOOL:.*]] = icmp ne i8 %[[ATOMIC_LOAD]], 0
 // CHECK:   ret i1 %[[TOBOOL]]
 
-// CHECK-LABEL: define internal void @"\01-[A0 setP:]"({{.*}} i1 noundef {{.*}})
+// CHECK-LABEL: define internal void @"\01-[A0 setP:]"({{.*}} i1 noundef zeroext {{.*}})
 // CHECK:   store atomic i8 %{{.*}}, ptr %{{.*}} seq_cst, align 1
 // CHECK:   ret void
 
@@ -14,7 +14,7 @@
 // CHECK:   %[[TOBOOL:.*]] = icmp ne i8 %[[ATOMIC_LOAD]], 0
 // CHECK:   ret i1 %[[TOBOOL]]
 
-// CHECK-LABEL: define internal void @"\01-[A1 setP:]"({{.*}} i1 noundef %p)
+// CHECK-LABEL: define internal void @"\01-[A1 setP:]"({{.*}} i1 noundef zeroext %p)
 // CHECK:   store atomic i8 %{{.*}}, ptr %{{.*}} unordered, align 1
 // CHECK:   ret void
 
diff --git a/llvm/include/llvm/ABI/TargetInfo.h b/llvm/include/llvm/ABI/TargetInfo.h
index 78d30125297e48..60af520a99a0a2 100644
--- a/llvm/include/llvm/ABI/TargetInfo.h
+++ b/llvm/include/llvm/ABI/TargetInfo.h
@@ -49,13 +49,13 @@ struct ABICompatInfo {
 
 /// How promotable integer arguments are passed on X86
 /// (-mextend-small-integers).
-enum class X86ExtendIntegerArgsKind {
-  /// Pass the argument directly, without extension in the caller.
-  Direct,
-  /// Extend in the caller, but do not assume the extension in the callee.
-  Conservative,
-  /// Extend in the caller and assume the extension in the callee.
-  Assumed,
+enum class SmallIntABICompatKind {
+  /// Compat with SysV ABI (high bits unspecified).
+  SysV,
+  /// Compat with old Clang ABI (high bits zero/sign-extended).
+  Clang,
+  /// Compat with both. Extend in caller, don't assume in callee.
+  Both,
 };
 
 /// Flags controlling X86-specific ABI compatibility behaviour.
@@ -66,13 +66,13 @@ struct X86ABICompatInfo : ABICompatInfo {
   bool HonorsRevision98 : 1;
   bool Clang11Compat : 1;
   bool ClassifyUnnamedBitFields : 1;
-  X86ExtendIntegerArgsKind ExtendIntegerArgs;
+  SmallIntABICompatKind SmallIntABICompat;
 
   X86ABICompatInfo()
       : PassInt128VectorsInMem(true), ReturnCXXRecordGreaterThan128InMem(true),
         ClassifyIntegerMMXAsSSE(true), HonorsRevision98(true),
         Clang11Compat(true), ClassifyUnnamedBitFields(true),
-        ExtendIntegerArgs(X86ExtendIntegerArgsKind::Assumed) {}
+        SmallIntABICompat(SmallIntABICompatKind::Both) {}
 };
 
 class TargetInfo {
diff --git a/llvm/lib/ABI/Targets/X86.cpp b/llvm/lib/ABI/Targets/X86.cpp
index a3500eea08b487..87ca7be885da0e 100644
--- a/llvm/lib/ABI/Targets/X86.cpp
+++ b/llvm/lib/ABI/Targets/X86.cpp
@@ -651,13 +651,13 @@ X86_64TargetInfo::classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
     // so that the parameter gets the right LLVM IR attributes.
     if (Hi == NoClass && ResType->isInteger()) {
       if (Ty->isInteger() && isPromotableInteger(cast<IntegerType>(Ty))) {
-        switch (getX86ABICompatInfo().ExtendIntegerArgs) {
-        case X86ExtendIntegerArgsKind::Assumed:
+        switch (getX86ABICompatInfo().SmallIntABICompat) {
+        case SmallIntABICompatKind::SysV:
+          break;
+        case SmallIntABICompatKind::Clang:
           return ArgInfo::getExtend(Ty);
-        case X86ExtendIntegerArgsKind::Conservative:
+        case SmallIntABICompatKind::Both:
           return ArgInfo::getConservativeExtend(Ty);
-        case X86ExtendIntegerArgsKind::Direct:
-          break;
         }
       }
     }

>From 87e5d4dbbf406f09756d9739241c0092b2dfa15c Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Wed, 28 Oct 2026 15:40:26 +0100
Subject: [PATCH 05/11] s/sysv/platform

I didn't realize that the change also affects win32, in which case
talking about sysv isn't right. Replace "sysv" ABI with "platform"
ABI.
---
 clang/include/clang/Basic/CodeGenOptions.def  |  2 +-
 clang/include/clang/Basic/CodeGenOptions.h    |  6 +--
 clang/include/clang/Options/Options.td        | 52 ++++++++++---------
 clang/lib/CodeGen/CodeGenModule.cpp           |  4 +-
 clang/lib/CodeGen/Targets/X86.cpp             |  2 +-
 .../CodeGen/X86/integer_argument_passing.c    |  8 +--
 llvm/include/llvm/ABI/TargetInfo.h            |  4 +-
 llvm/lib/ABI/Targets/X86.cpp                  |  2 +-
 8 files changed, 42 insertions(+), 38 deletions(-)

diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index ab2bface8ba37f..01b3084e5acf15 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -551,7 +551,7 @@ CODEGENOPT(ZOSPPA1Name, 1, 1, Benign)
 #include "DebugOptions.def"
 
 /// Which ABIs small integer argument passing on X86 platforms should be
-/// compatible with: SysV, Clang, Both.
+/// compatible with: Platform, Clang, Both.
 ENUM_CODEGENOPT(SmallIntABICompat, SmallIntABICompatKind, 2,
                 SmallIntABICompatKind::Both, Benign)
 
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index a26a3bad8835a8..85e5a30af02fe5 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -284,9 +284,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
   };
 
   enum class SmallIntABICompatKind {
-    SysV,  // Compat with SysV ABI (high bits unspecified).
-    Clang, // Compat with old Clang ABI (high bits zero/sign-extended).
-    Both,  // Compat with both. Extend in caller, don't assume in callee.
+    Platform, // Compat with platform ABI (high bits unspecified).
+    Clang,    // Compat with old Clang ABI (high bits zero/sign-extended).
+    Both,     // Compat with both. Extend in caller, don't assume in callee.
   };
 
   /// The code model to use (-mcmodel).
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 21d4bd1b099b5b..deace5a1b019f8 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5801,44 +5801,48 @@ def mzos_hlq_csslib_EQ : Joined<["-"], "mzos-hlq-csslib=">, MetaVarName<"<Csslib
 def msmall_int_abi_compat_EQ : Joined<["-"], "msmall-int-abi-compat=">,
   Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
   HelpText<"ABI compatibility for small integer arguments on X86: "
-           "'sysv' (High bits unspecified) | "
+           "'platform' (High bits unspecified) | "
            "'clang' (High bits zero/sign-extended) | "
            "'both' (High bits extended in caller, "
            "extension not assumed in callee)">,
-  Values<"sysv,clang,both">,
+  Values<"platform,clang,both">,
   NormalizedValuesScope<"CodeGenOptions::SmallIntABICompatKind">,
-  NormalizedValues<["SysV", "Clang", "Both"]>,
+  NormalizedValues<["Platform", "Clang", "Both"]>,
   MarshallingInfoEnum<CodeGenOpts<"SmallIntABICompat">, "Both">,
   DocBrief<[{
-Specifies how to handle small integer arguments on i386 and x86_64
-targets that generally follow the System V ABI, excluding Darwin and
-PlayStation targets. The value must be 'sysv', 'clang', or 'both'.
-The default behavior is 'both'.
-
-In the past, on System V i386 and x86_64 targets, Clang passed promotable
-integer arguments (non-variadic arguments with types smaller than 'int')
-using a parameter convention in which the caller was assumed to have
-sign-extended or zero-extended the argument to the width of an 'int'. This
-convention did not conform to the documented ABI for these targets, which
-does not require the caller to perform this extension. This can introduce
-incompatibilities with code generated by other compilers on these targets.
-
-If 'sysv' is used, promotable integer arguments will not be extended by the
-caller. This is conformant with the System V ABI, but may break compatibility
-with old Clang-built objects.
+Specifies how small integer arguments are passed on the following platforms:
+ * 32-bit x86 for operating systems other than Darwin and Playstation.
+ * 64-bit x86 for operating systems other than Windows, Darwin and PlayStation.
+
+The value must be 'platform', 'clang', or 'both'. The default behavior is
+'both'.
+
+In the past, Clang passed promotable integer arguments (non-variadic arguments
+with types smaller than 'int') using a parameter convention in which the caller
+was assumed to have sign-extended or zero-extended the argument to the width of
+an 'int'. This convention did not conform to the documented psABI for these
+targets, which does not require the caller to perform this extension. This
+can introduce incompatibilities with code generated by other compilers on these
+targets.
+
+If 'platform' is used, promotable integer arguments will not be extended by the
+caller. This is conformant with the platform psABI (such as the System V ABI),
+but may break compatibility with old Clang-built objects.
 
 If 'clang' is used, promotable integer arguments are extended by the caller,
 and the callee assumes this extension has happend. This restores the previous
 (before version 24) behavior of Clang, but may be incompatible with other
-compilers like GCC following the System V ABI.
+compilers like GCC following the platform ABI.
 
 If 'both' is used (the default), promotable integer types will be extended by
 the caller, but the callee will not assume that this extension has happened.
-This is compatible with both the System V ABI, and the old Clang ABI.
+This is compatible with both the platform ABI, and the old Clang ABI.
+
+The option has no effect on non-x86 targets, or when targeting one of the
+operating systems excluded above. Darwin and PlayStation use the Clang ABI as
+the platform ABI. 64-bit Windows never used argument extension in the first
+place.}]>;
 
-The option has no effect on non-X86 targets, and when targeting the Windows,
-Darwin and PlayStation operating systems. Windows never used argument extension
-in the first place, and Darwin/PlayStation follow the Clang ABI.}]>;
 def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group<m_Group>;
 def mno_global_merge : Flag<["-"], "mno-global-merge">, Group<m_Group>,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index beec300304d0bd..80fab1e211ac38 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -411,8 +411,8 @@ static void initializeX86ABICompatInfo(llvm::abi::X86ABICompatInfo &CompatInfo,
     CompatInfo.SmallIntABICompat = llvm::abi::SmallIntABICompatKind::Clang;
   } else {
     switch (CGOpts.getSmallIntABICompat()) {
-    case CodeGenOptions::SmallIntABICompatKind::SysV:
-      CompatInfo.SmallIntABICompat = llvm::abi::SmallIntABICompatKind::SysV;
+    case CodeGenOptions::SmallIntABICompatKind::Platform:
+      CompatInfo.SmallIntABICompat = llvm::abi::SmallIntABICompatKind::Platform;
       break;
     case CodeGenOptions::SmallIntABICompatKind::Clang:
       CompatInfo.SmallIntABICompat = llvm::abi::SmallIntABICompatKind::Clang;
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index 55cec7c8bb66db..a3803e5b1982fc 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -1003,7 +1003,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State,
   if (isPromotableIntegerTypeForABI(Ty)) {
     switch (getEffectiveSmallIntABICompat(getCodeGenOpts(),
                                           getTarget().getTriple())) {
-    case CodeGenOptions::SmallIntABICompatKind::SysV:
+    case CodeGenOptions::SmallIntABICompatKind::Platform:
       break;
     case CodeGenOptions::SmallIntABICompatKind::Clang:
       return InReg ? ABIArgInfo::getExtendInReg(Ty, CGT.ConvertType(Ty))
diff --git a/clang/test/CodeGen/X86/integer_argument_passing.c b/clang/test/CodeGen/X86/integer_argument_passing.c
index 12b06a85d49762..fac47918455ed8 100644
--- a/clang/test/CodeGen/X86/integer_argument_passing.c
+++ b/clang/test/CodeGen/X86/integer_argument_passing.c
@@ -18,18 +18,18 @@
 
 // Test -msmall-int-abi-compat flag
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=both %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-ASSUME-EXTENDED
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=sysv %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=platform %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-NO-ASSUME-EXTENDED
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=clang %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=both -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-NO-ASSUME-EXTENDED
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=sysv -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-NO-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=platform -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-NO-EXTEND,CALLEE-NO-ASSUME-EXTENDED
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=clang -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
 //
 // Check that the flag has no effect on targets with different platform ABI.
 // RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=both %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=sysv %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=platform %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
 // RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=clang %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
 // RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=both -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=sysv -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=platform -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
 // RUN: %clang_cc1 -triple x86_64-apple-darwin -msmall-int-abi-compat=clang -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CALLER-EXTEND,CALLEE-ASSUME-EXTENDED
 
 // CALLEE-ASSUME-EXTENDED: define{{.*}} i32 @ZeroExtend(i8 noundef zeroext %a, i16 noundef zeroext %b)
diff --git a/llvm/include/llvm/ABI/TargetInfo.h b/llvm/include/llvm/ABI/TargetInfo.h
index 60af520a99a0a2..09be0d2575d9ad 100644
--- a/llvm/include/llvm/ABI/TargetInfo.h
+++ b/llvm/include/llvm/ABI/TargetInfo.h
@@ -50,8 +50,8 @@ struct ABICompatInfo {
 /// How promotable integer arguments are passed on X86
 /// (-mextend-small-integers).
 enum class SmallIntABICompatKind {
-  /// Compat with SysV ABI (high bits unspecified).
-  SysV,
+  /// Compat with platform ABI (high bits unspecified).
+  Platform,
   /// Compat with old Clang ABI (high bits zero/sign-extended).
   Clang,
   /// Compat with both. Extend in caller, don't assume in callee.
diff --git a/llvm/lib/ABI/Targets/X86.cpp b/llvm/lib/ABI/Targets/X86.cpp
index 87ca7be885da0e..75a1ed8187dbbf 100644
--- a/llvm/lib/ABI/Targets/X86.cpp
+++ b/llvm/lib/ABI/Targets/X86.cpp
@@ -652,7 +652,7 @@ X86_64TargetInfo::classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
     if (Hi == NoClass && ResType->isInteger()) {
       if (Ty->isInteger() && isPromotableInteger(cast<IntegerType>(Ty))) {
         switch (getX86ABICompatInfo().SmallIntABICompat) {
-        case SmallIntABICompatKind::SysV:
+        case SmallIntABICompatKind::Platform:
           break;
         case SmallIntABICompatKind::Clang:
           return ArgInfo::getExtend(Ty);

>From 32e25870b8923710daaf4dc7bcb9b9b1a971bafc Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Wed, 28 Oct 2026 15:46:37 +0100
Subject: [PATCH 06/11] Adjust bool handling for platform ABI

---
 clang/lib/CodeGen/Targets/X86.cpp             | 28 +++++++++++++++----
 .../test/CodeGen/X86/bool_argument_passing.c  | 28 +++++++++++++++++++
 llvm/lib/ABI/Targets/X86.cpp                  |  5 ++++
 3 files changed, 55 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/CodeGen/X86/bool_argument_passing.c

diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index a3803e5b1982fc..098e21c110a9c9 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -1004,6 +1004,14 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State,
     switch (getEffectiveSmallIntABICompat(getCodeGenOpts(),
                                           getTarget().getTriple())) {
     case CodeGenOptions::SmallIntABICompatKind::Platform:
+      if (Ty->isBooleanType()) {
+        // Bool should be extended to 8-bits. We can't express this right now,
+        // so use conservative extension.
+        return InReg
+                   ? ABIArgInfo::getConservativeExtendInReg(Ty,
+                                                            CGT.ConvertType(Ty))
+                   : ABIArgInfo::getConservativeExtend(Ty, CGT.ConvertType(Ty));
+      }
       break;
     case CodeGenOptions::SmallIntABICompatKind::Clang:
       return InReg ? ABIArgInfo::getExtendInReg(Ty, CGT.ConvertType(Ty))
@@ -3014,14 +3022,22 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs,
       // Treat an enum type as its underlying type.
       if (const auto *ED = Ty->getAsEnumDecl())
         Ty = ED->getIntegerType();
-      auto Kind = getEffectiveSmallIntABICompat(getCodeGenOpts(),
-                                                getTarget().getTriple());
       if (Ty->isIntegralOrEnumerationType() &&
           isPromotableIntegerTypeForABI(Ty)) {
-      if (Kind == CodeGenOptions::SmallIntABICompatKind::Both)
-        return ABIArgInfo::getConservativeExtend(Ty, CGT.ConvertType(Ty));
-      else if (Kind == CodeGenOptions::SmallIntABICompatKind::Clang)
-        return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));
+        switch (getEffectiveSmallIntABICompat(getCodeGenOpts(),
+                                              getTarget().getTriple())) {
+        case CodeGenOptions::SmallIntABICompatKind::Platform:
+          if (Ty->isBooleanType()) {
+            // Bool should be extended to 8-bits. We can't express this right
+            // now, so use conservative extension.
+            return ABIArgInfo::getConservativeExtend(Ty, CGT.ConvertType(Ty));
+          }
+          break;
+        case CodeGenOptions::SmallIntABICompatKind::Clang:
+          return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));
+        case CodeGenOptions::SmallIntABICompatKind::Both:
+          return ABIArgInfo::getConservativeExtend(Ty, CGT.ConvertType(Ty));
+        }
       }
     }
 
diff --git a/clang/test/CodeGen/X86/bool_argument_passing.c b/clang/test/CodeGen/X86/bool_argument_passing.c
new file mode 100644
index 00000000000000..2ee4e122486781
--- /dev/null
+++ b/clang/test/CodeGen/X86/bool_argument_passing.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-BOTH
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=both %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-BOTH
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=clang %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-CLANG
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=platform %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-PLATFORM
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-BOTH
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=both -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-BOTH
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=clang -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-CLANG
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -msmall-int-abi-compat=platform -fexperimental-abi-lowering %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-PLATFORM
+
+// -msmall-int-abi-compat=platform only needs to extend to 8-bits in the caller
+// and can assume 8-bit extension in the callee. We currently can't express
+// this, so we perform full 32-bit extension in the caller and do not assume
+// any extension in the callee, making it the same as =both for the special
+// case of _Bool. In the future, we should model this more precisely.
+
+// CHECK-BOTH: define{{.*}} zeroext i1 @test(i1 noundef %x)
+// CHECK-CLANG: define{{.*}} zeroext i1 @test(i1 noundef zeroext %x)
+// CHECK-PLATFORM: define{{.*}} zeroext i1 @test(i1 noundef %x)
+_Bool test(_Bool x) {
+  return x;
+}
+
+_Bool test2(_Bool x) {
+// CHECK-BOTH: call zeroext i1 @test(i1 noundef zeroext %{{.*}})
+// CHECK-CLANG: call zeroext i1 @test(i1 noundef zeroext %{{.*}})
+// CHECK-PLATFORM: call zeroext i1 @test(i1 noundef zeroext %{{.*}})
+  return test(x);
+}
diff --git a/llvm/lib/ABI/Targets/X86.cpp b/llvm/lib/ABI/Targets/X86.cpp
index 75a1ed8187dbbf..97d1549c1538d4 100644
--- a/llvm/lib/ABI/Targets/X86.cpp
+++ b/llvm/lib/ABI/Targets/X86.cpp
@@ -653,6 +653,11 @@ X86_64TargetInfo::classifyArgumentType(const Type *Ty, unsigned FreeIntRegs,
       if (Ty->isInteger() && isPromotableInteger(cast<IntegerType>(Ty))) {
         switch (getX86ABICompatInfo().SmallIntABICompat) {
         case SmallIntABICompatKind::Platform:
+          if (cast<IntegerType>(Ty)->isBool()) {
+            // Bool should be extended to 8-bits. We can't express this right
+            // now, so use conservative extension.
+            return ArgInfo::getConservativeExtend(Ty);
+          }
           break;
         case SmallIntABICompatKind::Clang:
           return ArgInfo::getExtend(Ty);

>From 672cd556e5637202fb57635af8c6f473c5101e71 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Wed, 28 Oct 2026 16:11:02 +0100
Subject: [PATCH 07/11] Update ABI library test

---
 llvm/unittests/ABI/X86TargetInfoTest.cpp | 64 ++++++++++++++----------
 1 file changed, 38 insertions(+), 26 deletions(-)

diff --git a/llvm/unittests/ABI/X86TargetInfoTest.cpp b/llvm/unittests/ABI/X86TargetInfoTest.cpp
index 9da56f48400a26..dcc83e2c61b9f0 100644
--- a/llvm/unittests/ABI/X86TargetInfoTest.cpp
+++ b/llvm/unittests/ABI/X86TargetInfoTest.cpp
@@ -28,12 +28,12 @@ using llvm::abi::FieldInfo;
 using llvm::abi::FunctionInfo;
 using llvm::abi::RecordFlags;
 using llvm::abi::RequiredArgs;
+using llvm::abi::SmallIntABICompatKind;
 using llvm::abi::StructPacking;
 using llvm::abi::TargetInfo;
 using llvm::abi::TypeBuilder;
 using llvm::abi::X86ABICompatInfo;
 using llvm::abi::X86AVXABILevel;
-using llvm::abi::X86ExtendIntegerArgsKind;
 
 class X86TargetInfoTest : public ::testing::Test {
 protected:
@@ -43,6 +43,7 @@ class X86TargetInfoTest : public ::testing::Test {
   const ABIType *I16;
   const ABIType *I32;
   const ABIType *I64;
+  const ABIType *U8;
   const ABIType *F32;
   const ABIType *F64;
   /// An x87 long double: 80 bits of value in 16 bytes of storage.
@@ -61,6 +62,7 @@ class X86TargetInfoTest : public ::testing::Test {
         I16(TB.getIntegerType(16, llvm::Align(2), /*Signed=*/true)),
         I32(TB.getIntegerType(32, llvm::Align(4), /*Signed=*/true)),
         I64(TB.getIntegerType(64, llvm::Align(8), /*Signed=*/true)),
+        U8(TB.getIntegerType(8, llvm::Align(1), /*Signed=*/false)),
         F32(TB.getFloatType(llvm::APFloat::IEEEsingle(), llvm::Align(4))),
         F64(TB.getFloatType(llvm::APFloat::IEEEdouble(), llvm::Align(8))),
         F80(TB.getFloatType(llvm::APFloat::x87DoubleExtended(),
@@ -143,6 +145,12 @@ static void expectExtendInteger(const ArgInfo &Info, const ABIType *Ty,
   EXPECT_EQ(Info.getCoerceToType(), Ty);
 }
 
+static void expectConservativeExtendInteger(const ArgInfo &Info,
+                                            const ABIType *Ty, bool IsSigned) {
+  EXPECT_TRUE(Info.isConservativeExtend());
+  EXPECT_EQ(Info.isSignExt(), IsSigned);
+  EXPECT_EQ(Info.getCoerceToType(), Ty);
+}
 static void expectInteger(const ABIType *Ty, unsigned Bits) {
   const auto *IT = llvm::dyn_cast<llvm::abi::IntegerType>(Ty);
   ASSERT_NE(IT, nullptr);
@@ -978,11 +986,11 @@ TEST_F(X86TargetInfoTest, IntReturnExtension) {
 }
 
 TEST_F(X86TargetInfoTest, IntArgExtension) {
-  auto ClassifyArg = [&](const ABIType *ArgTy, X86ExtendIntegerArgsKind Kind,
+  auto ClassifyArg = [&](const ABIType *ArgTy, SmallIntABICompatKind Kind,
                          std::unique_ptr<FunctionInfo> &FI,
                          std::unique_ptr<TargetInfo> &TI) -> const ArgInfo & {
     X86ABICompatInfo Compat;
-    Compat.ExtendIntegerArgs = Kind;
+    Compat.SmallIntABICompat = Kind;
     TI = target(X86AVXABILevel::None, Compat);
     FI = FunctionInfo::create(llvm::CallingConv::C, Void, {ArgTy});
     TI->computeInfo(*FI);
@@ -991,35 +999,39 @@ TEST_F(X86TargetInfoTest, IntArgExtension) {
   std::unique_ptr<FunctionInfo> FI;
   std::unique_ptr<TargetInfo> TI;
 
-  // Assumed: extend in the caller and assume the extension in the callee.
-  expectExtendInteger(
-      ClassifyArg(I8, X86ExtendIntegerArgsKind::Assumed, FI, TI), I8,
+  // Clang: extend in the caller and assume the extension in the callee.
+  expectExtendInteger(ClassifyArg(I8, SmallIntABICompatKind::Clang, FI, TI), I8,
+                      /*IsSigned=*/true);
+  expectExtendInteger(ClassifyArg(U8, SmallIntABICompatKind::Clang, FI, TI), U8,
+                      /*IsSigned=*/false);
+  expectExtendInteger(ClassifyArg(Bool, SmallIntABICompatKind::Clang, FI, TI),
+                      Bool, /*IsSigned=*/false);
+
+  // Both: extend in the caller, but do not assume it in the callee.
+  expectConservativeExtendInteger(
+      ClassifyArg(I8, SmallIntABICompatKind::Both, FI, TI), I8,
       /*IsSigned=*/true);
-  expectExtendInteger(
-      ClassifyArg(Bool, X86ExtendIntegerArgsKind::Assumed, FI, TI), Bool,
+  expectConservativeExtendInteger(
+      ClassifyArg(U8, SmallIntABICompatKind::Both, FI, TI), U8,
+      /*IsSigned=*/false);
+  expectConservativeExtendInteger(
+      ClassifyArg(Bool, SmallIntABICompatKind::Both, FI, TI), Bool,
       /*IsSigned=*/false);
 
-  // Conservative: extend in the caller, but do not assume it in the callee.
-  for (auto [Ty, IsSigned] :
-       {std::pair(I8, true), std::pair(I16, true), std::pair(Bool, false)}) {
-    const ArgInfo &Info =
-        ClassifyArg(Ty, X86ExtendIntegerArgsKind::Conservative, FI, TI);
-    EXPECT_TRUE(Info.isConservativeExtend());
-    EXPECT_EQ(Info.isSignExt(), IsSigned);
-    EXPECT_EQ(Info.isZeroExt(), !IsSigned);
-    EXPECT_EQ(Info.getCoerceToType(), Ty);
-  }
-
-  // Direct: no extension at all.
-  expectDirectInteger(ClassifyArg(I8, X86ExtendIntegerArgsKind::Direct, FI, TI),
+  // Platform: no extension at all.
+  expectDirectInteger(ClassifyArg(I8, SmallIntABICompatKind::Platform, FI, TI),
                       8);
-  expectDirectInteger(
-      ClassifyArg(I16, X86ExtendIntegerArgsKind::Direct, FI, TI), 16);
+  expectDirectInteger(ClassifyArg(U8, SmallIntABICompatKind::Platform, FI, TI),
+                      8);
+  // Except for booleans, which need to be zero-extended to 8 bits. As we
+  // can't express this right now, us conservative extension instead.
+  expectConservativeExtendInteger(
+      ClassifyArg(Bool, SmallIntABICompatKind::Both, FI, TI), Bool,
+      /*IsSigned=*/false);
 
   // int is never extended.
-  for (auto Kind : {X86ExtendIntegerArgsKind::Assumed,
-                    X86ExtendIntegerArgsKind::Conservative,
-                    X86ExtendIntegerArgsKind::Direct})
+  for (auto Kind : {SmallIntABICompatKind::Platform,
+                    SmallIntABICompatKind::Clang, SmallIntABICompatKind::Both})
     expectDirectInteger(ClassifyArg(I32, Kind, FI, TI), 32);
 }
 

>From 15ee1af22a098edb21825a0684a576af383274fb Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Thu, 29 Oct 2026 10:10:03 +0100
Subject: [PATCH 08/11] Use Conservative flag instead of separate
 ConservativeExtend kind

These need to be handled the same way in almost all places -- just
the attribtue assignment differs. I think it's cleaner to always
use Extend with an extra flag.
---
 clang/include/clang/CodeGen/CGFunctionInfo.h  | 79 ++++++++-----------
 .../Transforms/CallConvLoweringPass.cpp       |  4 +-
 clang/lib/CodeGen/CGCall.cpp                  | 56 +++++--------
 clang/lib/CodeGen/TargetInfo.cpp              |  3 -
 clang/lib/CodeGen/Targets/X86.cpp             |  1 -
 clang/lib/CodeGen/Targets/XCore.cpp           |  1 -
 llvm/include/llvm/ABI/FunctionInfo.h          | 35 ++++----
 llvm/unittests/ABI/X86TargetInfoTest.cpp      |  4 +-
 8 files changed, 74 insertions(+), 109 deletions(-)

diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h
index c24c67b77bfbb9..e25ee40ceae383 100644
--- a/clang/include/clang/CodeGen/CGFunctionInfo.h
+++ b/clang/include/clang/CodeGen/CGFunctionInfo.h
@@ -43,11 +43,6 @@ class ABIArgInfo {
     /// but also emit a zero/sign extension attribute.
     Extend,
 
-    /// ConservativeExtend - Valid only for integer argument types. Same as
-    /// 'Extend' but do not assume in the callee that the caller actually did
-    /// the extension
-    ConservativeExtend,
-
     /// Indirect - Pass the argument indirectly via a hidden pointer with the
     /// specified alignment (0 indicates default alignment) and address space.
     Indirect,
@@ -126,10 +121,11 @@ class ABIArgInfo {
   bool CanBeFlattened: 1;   // isDirect()
   bool SignExt : 1;         // isExtend()
   bool ZeroExt : 1;         // isExtend()
+  bool Conservative : 1;    // isExtend()
 
   bool canHavePaddingType() const {
     return isDirect() || isExtend() || isIndirect() || isIndirectAliased() ||
-           isExpand() || isTargetSpecific() || isConservativeExtend();
+           isExpand() || isTargetSpecific();
   }
   void setPaddingType(llvm::Type *T) {
     assert(canHavePaddingType());
@@ -144,10 +140,10 @@ class ABIArgInfo {
 public:
   ABIArgInfo(Kind K = Direct)
       : TypeData(nullptr), PaddingType(nullptr), DirectAttr{0, 0}, TheKind(K),
-        PaddingInReg(false), InAllocaSRet(false),
-        InAllocaIndirect(false), IndirectByVal(false), IndirectRealign(false),
-        SRetAfterThis(false), InReg(false), CanBeFlattened(false),
-        SignExt(false), ZeroExt(false) {}
+        PaddingInReg(false), InAllocaSRet(false), InAllocaIndirect(false),
+        IndirectByVal(false), IndirectRealign(false), SRetAfterThis(false),
+        InReg(false), CanBeFlattened(false), SignExt(false), ZeroExt(false),
+        Conservative(false) {}
 
   static ABIArgInfo getDirect(llvm::Type *T = nullptr, unsigned Offset = 0,
                               llvm::Type *Padding = nullptr,
@@ -212,16 +208,8 @@ class ABIArgInfo {
 
   static ABIArgInfo getConservativeExtend(QualType Ty,
                                           llvm::Type *T = nullptr) {
-    assert(Ty->isIntegralOrEnumerationType() && "Unexpected QualType");
-    auto AI = ABIArgInfo(ConservativeExtend);
-    AI.setCoerceToType(T);
-    AI.setPaddingType(nullptr);
-    AI.setDirectOffset(0);
-    AI.setDirectAlign(0);
-    if (Ty->hasSignedIntegerRepresentation())
-      AI.setSignExt(true);
-    else
-      AI.setZeroExt(true);
+    auto AI = getExtend(Ty, T);
+    AI.setConservative(true);
     return AI;
   }
 
@@ -354,66 +342,65 @@ class ABIArgInfo {
   bool isExpand() const { return TheKind == Expand; }
   bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
   bool isTargetSpecific() const { return TheKind == TargetSpecific; }
-  bool isConservativeExtend() const { return TheKind == ConservativeExtend; }
 
   bool canHaveCoerceToType() const {
     return isDirect() || isExtend() || isCoerceAndExpand() ||
-           isTargetSpecific() || isConservativeExtend();
+           isTargetSpecific();
   }
 
-  // Direct/Extend/ConservativeExtend accessors
+  // Direct/Extend accessors
   unsigned getDirectOffset() const {
-    assert((isDirect() || isExtend() || isTargetSpecific() ||
-            isConservativeExtend()) &&
-           "Invalid kind!");
+    assert((isDirect() || isExtend() || isTargetSpecific()) && "Invalid kind!");
     return DirectAttr.Offset;
   }
   void setDirectOffset(unsigned Offset) {
-    assert((isDirect() || isExtend() || isTargetSpecific() ||
-            isConservativeExtend()) &&
-           "Invalid kind");
+    assert((isDirect() || isExtend() || isTargetSpecific()) && "Invalid kind");
     DirectAttr.Offset = Offset;
   }
 
   unsigned getDirectAlign() const {
-    assert((isDirect() || isExtend() || isTargetSpecific() ||
-            isConservativeExtend()) &&
-           "Invalid kind");
+    assert((isDirect() || isExtend() || isTargetSpecific()) && "Invalid kind");
     return DirectAttr.Align;
   }
   void setDirectAlign(unsigned Align) {
-    assert((isDirect() || isExtend() || isTargetSpecific() ||
-            isConservativeExtend()) &&
-           "Invalid kind");
+    assert((isDirect() || isExtend() || isTargetSpecific()) && "Invalid kind");
     DirectAttr.Align = Align;
   }
 
   bool isSignExt() const {
-    assert((isExtend() || isConservativeExtend()) &&
-           (SignExt + ZeroExt <= 1) && "Invalid kind / flags!");
+    assert(isExtend() && (SignExt + ZeroExt <= 1) && "Invalid kind / flags!");
     return SignExt;
   }
   void setSignExt(bool SExt) {
-    assert((isExtend() || isConservativeExtend()) && "Invalid kind!");
+    assert(isExtend() && "Invalid kind!");
     SignExt = SExt;
   }
 
   bool isZeroExt() const {
-    assert((isExtend() || isConservativeExtend()) && (SignExt + ZeroExt <= 1) &&
-           "Invalid kind / flags!");
+    assert(isExtend() && (SignExt + ZeroExt <= 1) && "Invalid kind / flags!");
     return ZeroExt;
   }
   void setZeroExt(bool ZExt) {
-    assert((isExtend() || isConservativeExtend()) && "Invalid kind!");
+    assert(isExtend() && "Invalid kind!");
     ZeroExt = ZExt;
   }
 
   bool isNoExt() const {
-    assert((isExtend() || isConservativeExtend()) && (SignExt + ZeroExt <= 1) &&
-           "Invalid kind / flags!");
+    assert(isExtend() && (SignExt + ZeroExt <= 1) && "Invalid kind / flags!");
     return !SignExt && !ZeroExt;
   }
 
+  /// Whether the extension is conservative, i.e. the caller should extend, but
+  /// the callee not assume the extension. Only supported for arguments.
+  bool isConservative() const {
+    assert(isExtend() && "Invalid kind");
+    return Conservative;
+  }
+  void setConservative(bool Val) {
+    assert(isExtend() && "Invalid kind");
+    Conservative = Val;
+  }
+
   llvm::Type *getPaddingType() const {
     return (canHavePaddingType() ? PaddingType : nullptr);
   }
@@ -456,15 +443,13 @@ class ABIArgInfo {
   }
 
   bool getInReg() const {
-    assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific() ||
-            isConservativeExtend()) &&
+    assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific()) &&
            "Invalid kind!");
     return InReg;
   }
 
   void setInReg(bool IR) {
-    assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific() ||
-            isConservativeExtend()) &&
+    assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific()) &&
            "Invalid kind!");
     InReg = IR;
   }
diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
index 10a5bb5f9b7dfb..ed12322a4c6bba 100644
--- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
@@ -673,8 +673,8 @@ convertABIArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx,
   // there is no offset to honor here.
   // A conservative extension is performed by the caller, but the callee does
   // not get to assume it, so its attribute only goes on call sites.
-  if (info.isExtend() || info.isConservativeExtend()) {
-    bool onCallSiteOnly = info.isConservativeExtend();
+  if (info.isExtend()) {
+    bool onCallSiteOnly = info.isConservative();
     if (isa_and_present<cir::BoolType>(origTy))
       return ArgClassification::getExtend(nullptr, info.isSignExt(),
                                           onCallSiteOnly);
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 67097fbca8b11c..12959d6d3f3f8c 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -876,8 +876,6 @@ static const char *abiKindToString(ABIArgInfo::Kind K) {
     return "Direct";
   case ABIArgInfo::Extend:
     return "Extend";
-  case ABIArgInfo::ConservativeExtend:
-    return "ConservativeExtend";
   case ABIArgInfo::Indirect:
     return "Indirect";
   case ABIArgInfo::IndirectAliased:
@@ -965,9 +963,10 @@ void CodeGenModule::computeABIInfoUsingLib(CGFunctionInfo &FI) {
 
     switch (Res.getKind()) {
     case ABIArgInfo::Extend:
-    case ABIArgInfo::ConservativeExtend:
       CheckSimple(Target.isSignExt(), Res.isSignExt(), "SignExt");
       CheckSimple(Target.isZeroExt(), Res.isZeroExt(), "ZeroExt");
+      CheckSimple(Target.isConservative(), Res.isConservative(),
+                  "Conservative");
       [[fallthrough]];
     case ABIArgInfo::Direct:
       CheckSimple(Target.getDirectAlign(), Res.getDirectAlign(), "DirectAlign");
@@ -1043,18 +1042,6 @@ ABIArgInfo CodeGenModule::convertABIArgInfo(const llvm::abi::ArgInfo &AbiInfo,
                                  /*Padding=*/nullptr,
                                  AbiInfo.getCanBeFlattened(), DirectAlign);
   }
-  case llvm::abi::ArgInfo::ConservativeExtend: {
-    llvm::Type *CoercedType = nullptr;
-    if (AbiInfo.getCoerceToType())
-      CoercedType = AbiReverseMapper->convertType(AbiInfo.getCoerceToType());
-    if (!CoercedType)
-      CoercedType = getTypes().ConvertType(Type);
-    ABIArgInfo AI = ABIArgInfo::getConservativeExtend(
-        useFirstFieldIfTransparentUnion(Type), CoercedType);
-    AI.setSignExt(AbiInfo.isSignExt());
-    AI.setZeroExt(AbiInfo.isZeroExt());
-    return AI;
-  }
   case llvm::abi::ArgInfo::Extend: {
     llvm::Type *CoercedType = nullptr;
     if (AbiInfo.getCoerceToType())
@@ -1066,11 +1053,16 @@ ABIArgInfo CodeGenModule::convertABIArgInfo(const llvm::abi::ArgInfo &AbiInfo,
     // useFirstFieldIfTransparentUnion.  Passing the union type to
     // ABIArgInfo::getSignExtend would trip its integral-type assert.
     QualType ExtendType = useFirstFieldIfTransparentUnion(Type);
+    // TODO
+    ABIArgInfo Res;
     if (AbiInfo.isSignExt())
-      return ABIArgInfo::getSignExtend(ExtendType, CoercedType);
-    if (AbiInfo.isZeroExt())
-      return ABIArgInfo::getZeroExtend(ExtendType, CoercedType);
-    return ABIArgInfo::getExtend(ExtendType, CoercedType);
+      Res = ABIArgInfo::getSignExtend(ExtendType, CoercedType);
+    else if (AbiInfo.isZeroExt())
+      Res = ABIArgInfo::getZeroExtend(ExtendType, CoercedType);
+    else
+      Res = ABIArgInfo::getNoExtend(cast<llvm::IntegerType>(CoercedType));
+    Res.setConservative(AbiInfo.isConservative());
+    return Res;
   }
   case llvm::abi::ArgInfo::Indirect: {
     CharUnits Alignment =
@@ -1997,8 +1989,7 @@ void ClangToLLVMArgMapping::construct(const ASTContext &Context,
     switch (AI.getKind()) {
     case ABIArgInfo::TargetSpecific:
     case ABIArgInfo::Extend:
-    case ABIArgInfo::Direct:
-    case ABIArgInfo::ConservativeExtend: {
+    case ABIArgInfo::Direct: {
       // FIXME: handle sseregparm someday...
       llvm::StructType *STy = dyn_cast<llvm::StructType>(AI.getCoerceToType());
       if (AI.isDirect() && AI.getCanBeFlattened() && STy) {
@@ -2110,7 +2101,6 @@ llvm::FunctionType *CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
   case ABIArgInfo::TargetSpecific:
   case ABIArgInfo::Extend:
   case ABIArgInfo::Direct:
-  case ABIArgInfo::ConservativeExtend:
     resultType = retAI.getCoerceToType();
     break;
 
@@ -2183,8 +2173,7 @@ llvm::FunctionType *CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
       break;
     case ABIArgInfo::TargetSpecific:
     case ABIArgInfo::Extend:
-    case ABIArgInfo::Direct:
-    case ABIArgInfo::ConservativeExtend: {
+    case ABIArgInfo::Direct: {
       // Fast-isel and the optimizer generally like scalar values better than
       // FCAs, so we flatten them if this is safe to do for this argument.
       llvm::Type *argType = ArgInfo.getCoerceToType();
@@ -2654,9 +2643,7 @@ static bool DetermineNoUndef(QualType QTy, CodeGenTypes &Types,
   if (AI.getKind() == ABIArgInfo::Indirect ||
       AI.getKind() == ABIArgInfo::IndirectAliased)
     return true;
-  if ((AI.getKind() == ABIArgInfo::Extend ||
-       AI.getKind() == ABIArgInfo::ConservativeExtend) &&
-      !AI.isNoExt())
+  if (AI.getKind() == ABIArgInfo::Extend && !AI.isNoExt())
     return true;
   if (!DL.typeSizeEqualsStoreSize(Ty))
     // TODO: This will result in a modest amount of values not marked noundef
@@ -3053,7 +3040,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
 
   switch (RetAI.getKind()) {
   case ABIArgInfo::Extend:
-  case ABIArgInfo::ConservativeExtend:
+    assert(!RetAI.isConservative() && "Conservative return not supported");
     if (RetAI.isSignExt())
       RetAttrs.addAttribute(llvm::Attribute::SExt);
     else if (RetAI.isZeroExt())
@@ -3214,10 +3201,9 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
     // sense to do it here because parameters are so messed up.
     switch (AI.getKind()) {
     case ABIArgInfo::Extend:
-    case ABIArgInfo::ConservativeExtend:
-      // Under ConservativeExtend, add sext/zext only on the call site; the
+      // Under conservative extension, add sext/zext only on the call site; the
       // callee does not get to assume extension.
-      if (AttrOnCallSite || AI.getKind() == ABIArgInfo::Extend) {
+      if (AttrOnCallSite || !AI.isConservative()) {
         if (AI.isSignExt())
           Attrs.addAttribute(llvm::Attribute::SExt);
         else if (AI.isZeroExt())
@@ -3641,8 +3627,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
     }
 
     case ABIArgInfo::Extend:
-    case ABIArgInfo::Direct:
-    case ABIArgInfo::ConservativeExtend: {
+    case ABIArgInfo::Direct: {
       auto AI = Fn->getArg(FirstIRArg);
       llvm::Type *LTy = ConvertType(Arg->getType());
 
@@ -4494,7 +4479,6 @@ void CodeGenFunction::EmitFunctionEpilog(
 
   case ABIArgInfo::Extend:
   case ABIArgInfo::Direct:
-  case ABIArgInfo::ConservativeExtend:
     if (RetAI.getCoerceToType() == ConvertType(RetTy) &&
         RetAI.getDirectOffset() == 0) {
       // The internal return value temp always will have pointer-to-return-type
@@ -6004,8 +5988,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
       break;
 
     case ABIArgInfo::Extend:
-    case ABIArgInfo::Direct:
-    case ABIArgInfo::ConservativeExtend: {
+    case ABIArgInfo::Direct: {
       if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) &&
           ArgInfo.getCoerceToType() == ConvertType(info_it->type) &&
           ArgInfo.getDirectOffset() == 0) {
@@ -6782,7 +6765,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
         return GetUndefRValue(RetTy);
 
       case ABIArgInfo::Extend:
-      case ABIArgInfo::ConservativeExtend:
       case ABIArgInfo::Direct: {
         llvm::Type *RetIRTy = ConvertType(RetTy);
         if (RetAI.getCoerceToType() == RetIRTy &&
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index c2873605e9e008..86f96b72170032 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -70,9 +70,6 @@ LLVM_DUMP_METHOD void ABIArgInfo::dump() const {
     else
       OS << "null";
     break;
-  case ConservativeExtend:
-    OS << "ConservativeExtend";
-    break;
   }
   OS << ")\n";
 }
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index 098e21c110a9c9..caf1769ea52bad 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -1143,7 +1143,6 @@ static bool isArgInAlloca(const ABIArgInfo &Info) {
   case ABIArgInfo::Indirect:
   case ABIArgInfo::Direct:
   case ABIArgInfo::Extend:
-  case ABIArgInfo::ConservativeExtend:
     return !Info.getInReg();
   case ABIArgInfo::Expand:
   case ABIArgInfo::CoerceAndExpand:
diff --git a/clang/lib/CodeGen/Targets/XCore.cpp b/clang/lib/CodeGen/Targets/XCore.cpp
index b0fdad93b55df2..f9726ec0a661d4 100644
--- a/clang/lib/CodeGen/Targets/XCore.cpp
+++ b/clang/lib/CodeGen/Targets/XCore.cpp
@@ -158,7 +158,6 @@ RValue XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
   case ABIArgInfo::CoerceAndExpand:
   case ABIArgInfo::InAlloca:
   case ABIArgInfo::TargetSpecific:
-  case ABIArgInfo::ConservativeExtend:
     llvm_unreachable("Unsupported ABI kind for va_arg");
   case ABIArgInfo::Ignore:
     Val = Address(llvm::UndefValue::get(ArgPtrTy), ArgTy, TypeAlign);
diff --git a/llvm/include/llvm/ABI/FunctionInfo.h b/llvm/include/llvm/ABI/FunctionInfo.h
index 0a6631fe3466e9..24c50c204cb78d 100644
--- a/llvm/include/llvm/ABI/FunctionInfo.h
+++ b/llvm/include/llvm/ABI/FunctionInfo.h
@@ -36,9 +36,6 @@ class ArgInfo {
     /// Valid only for integer argument types. Same as 'direct' but also emit a
     /// zero/sign extension attribute.
     Extend,
-    /// Valid only for integer argument types. Same as 'Extend', but the callee
-    /// does not get to assume that the caller actually did the extension.
-    ConservativeExtend,
     /// Pass the argument indirectly via a hidden pointer with the specified
     /// alignment and address space.
     Indirect,
@@ -81,6 +78,7 @@ class ArgInfo {
   Kind TheKind;
   bool SignExt : 1;
   bool ZeroExt : 1;
+  bool Conservative : 1;
   bool IndirectByVal : 1;
   bool IndirectRealign : 1;
   bool CanBeFlattened : 1;
@@ -88,9 +86,9 @@ class ArgInfo {
   unsigned NeededSseRegs : 3;
 
   ArgInfo(Kind K = Direct)
-      : TheKind(K), SignExt(false), ZeroExt(false), IndirectByVal(false),
-        IndirectRealign(false), CanBeFlattened(false), NeededIntRegs(0),
-        NeededSseRegs(0) {}
+      : TheKind(K), SignExt(false), ZeroExt(false), Conservative(false),
+        IndirectByVal(false), IndirectRealign(false), CanBeFlattened(false),
+        NeededIntRegs(0), NeededSseRegs(0) {}
 
 public:
   /// \param T The type to coerce to. If null, the argument's original type is
@@ -134,7 +132,7 @@ class ArgInfo {
 
   static ArgInfo getConservativeExtend(const Type *T) {
     ArgInfo AI = getExtend(T);
-    AI.TheKind = ConservativeExtend;
+    AI.Conservative = true;
     return AI;
   }
 
@@ -208,12 +206,10 @@ class ArgInfo {
   bool isIndirectAliased() const { return TheKind == IndirectAliased; }
   bool isIgnore() const { return TheKind == Ignore; }
   bool isExtend() const { return TheKind == Extend; }
-  bool isConservativeExtend() const { return TheKind == ConservativeExtend; }
   bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
 
   unsigned getDirectOffset() const {
-    assert((isDirect() || isExtend() || isConservativeExtend()) &&
-           "Not a direct or extend kind");
+    assert((isDirect() || isExtend()) && "Not a direct or extend kind");
     return DirectAttr.Offset;
   }
 
@@ -230,8 +226,7 @@ class ArgInfo {
   }
 
   MaybeAlign getDirectAlign() const {
-    assert((isDirect() || isExtend() || isConservativeExtend()) &&
-           "Not a direct or extend kind");
+    assert((isDirect() || isExtend()) && "Not a direct or extend kind");
     return Alignment;
   }
 
@@ -266,23 +261,29 @@ class ArgInfo {
   }
 
   bool isSignExt() const {
-    assert((isExtend() || isConservativeExtend()) && "Invalid Kind!");
+    assert(isExtend() && "Invalid Kind!");
     return SignExt;
   }
 
   bool isZeroExt() const {
-    assert((isExtend() || isConservativeExtend()) && "Invalid Kind!");
+    assert(isExtend() && "Invalid Kind!");
     return ZeroExt;
   }
 
   bool isNoExt() const {
-    assert((isExtend() || isConservativeExtend()) && "Invalid Kind!");
+    assert(isExtend() && "Invalid Kind!");
     return !SignExt && !ZeroExt;
   }
 
+  /// Whether the extension is conservative, i.e. the caller should extend, but
+  /// the callee not assume the extension. Only supported for arguments.
+  bool isConservative() const {
+    assert(isExtend() && "Invalid Kind!");
+    return Conservative;
+  }
+
   const Type *getCoerceToType() const {
-    assert((isDirect() || isExtend() || isConservativeExtend() ||
-            isCoerceAndExpand()) &&
+    assert((isDirect() || isExtend() || isCoerceAndExpand()) &&
            "Invalid Kind!");
     return CoercionType;
   }
diff --git a/llvm/unittests/ABI/X86TargetInfoTest.cpp b/llvm/unittests/ABI/X86TargetInfoTest.cpp
index dcc83e2c61b9f0..0edcd3dd6c277e 100644
--- a/llvm/unittests/ABI/X86TargetInfoTest.cpp
+++ b/llvm/unittests/ABI/X86TargetInfoTest.cpp
@@ -141,13 +141,15 @@ static void expectDirectInteger(const ArgInfo &Info, unsigned Bits) {
 static void expectExtendInteger(const ArgInfo &Info, const ABIType *Ty,
                                 bool IsSigned) {
   EXPECT_TRUE(Info.isExtend());
+  EXPECT_TRUE(!Info.isConservative());
   EXPECT_EQ(Info.isSignExt(), IsSigned);
   EXPECT_EQ(Info.getCoerceToType(), Ty);
 }
 
 static void expectConservativeExtendInteger(const ArgInfo &Info,
                                             const ABIType *Ty, bool IsSigned) {
-  EXPECT_TRUE(Info.isConservativeExtend());
+  EXPECT_TRUE(Info.isExtend());
+  EXPECT_TRUE(Info.isConservative());
   EXPECT_EQ(Info.isSignExt(), IsSigned);
   EXPECT_EQ(Info.getCoerceToType(), Ty);
 }

>From cf184823d21a08c097ccbd2c78b30aa9bae6a338 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Thu, 29 Oct 2026 10:33:44 +0100
Subject: [PATCH 09/11] Drop unnecessary changes

---
 clang/include/clang/CodeGen/CGFunctionInfo.h | 12 ++++++++----
 clang/lib/CodeGen/CGCall.cpp                 |  1 -
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h
index e25ee40ceae383..bbb96bea04dc76 100644
--- a/clang/include/clang/CodeGen/CGFunctionInfo.h
+++ b/clang/include/clang/CodeGen/CGFunctionInfo.h
@@ -350,20 +350,24 @@ class ABIArgInfo {
 
   // Direct/Extend accessors
   unsigned getDirectOffset() const {
-    assert((isDirect() || isExtend() || isTargetSpecific()) && "Invalid kind!");
+    assert((isDirect() || isExtend() || isTargetSpecific()) &&
+           "Not a direct or extend or target specific kind");
     return DirectAttr.Offset;
   }
   void setDirectOffset(unsigned Offset) {
-    assert((isDirect() || isExtend() || isTargetSpecific()) && "Invalid kind");
+    assert((isDirect() || isExtend() || isTargetSpecific()) &&
+           "Not a direct or extend or target specific kind");
     DirectAttr.Offset = Offset;
   }
 
   unsigned getDirectAlign() const {
-    assert((isDirect() || isExtend() || isTargetSpecific()) && "Invalid kind");
+    assert((isDirect() || isExtend() || isTargetSpecific()) &&
+           "Not a direct or extend or target specific kind");
     return DirectAttr.Align;
   }
   void setDirectAlign(unsigned Align) {
-    assert((isDirect() || isExtend() || isTargetSpecific()) && "Invalid kind");
+    assert((isDirect() || isExtend() || isTargetSpecific()) &&
+           "Not a direct or extend or target specific kind");
     DirectAttr.Align = Align;
   }
 
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 12959d6d3f3f8c..4344b62b6f1c54 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -1053,7 +1053,6 @@ ABIArgInfo CodeGenModule::convertABIArgInfo(const llvm::abi::ArgInfo &AbiInfo,
     // useFirstFieldIfTransparentUnion.  Passing the union type to
     // ABIArgInfo::getSignExtend would trip its integral-type assert.
     QualType ExtendType = useFirstFieldIfTransparentUnion(Type);
-    // TODO
     ABIArgInfo Res;
     if (AbiInfo.isSignExt())
       Res = ABIArgInfo::getSignExtend(ExtendType, CoercedType);

>From 270d4d21a2b87c94cfc2dea73c9bcd1f610cc787 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Thu, 29 Oct 2026 11:39:46 +0100
Subject: [PATCH 10/11] Explicitly specify triple in test

The XFAIL list here is getting silly and confusing. What this
test actually needs is a target where the struct is passed in
two args and the signed char needs signext. sparc64 and mips64
work for this purpose, while most others don't (e.g. becuase
they use an array instead of two arguments, or don't use signext).
---
 clang/test/CodeGen/2007-06-18-SextAttrAggregate.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/clang/test/CodeGen/2007-06-18-SextAttrAggregate.c b/clang/test/CodeGen/2007-06-18-SextAttrAggregate.c
index d0a830e84acfb2..9f7eb96b35179a 100644
--- a/clang/test/CodeGen/2007-06-18-SextAttrAggregate.c
+++ b/clang/test/CodeGen/2007-06-18-SextAttrAggregate.c
@@ -1,15 +1,9 @@
-// RUN: %clang_cc1 -no-enable-noundef-analysis %s -o - -emit-llvm | FileCheck %s
-// XFAIL: target={{(aarch64|arm64).*}}, target=x86_64-pc-windows-msvc, target=x86_64-{{(pc|w64)}}-windows-gnu, target=x86_64-pc-windows-cygnus, target=x86_64-{{.*}}-linux{{.*}}
+// RUN: %clang_cc1 -triple=sparc64-unknown-linux-gnu -no-enable-noundef-analysis %s -o - -emit-llvm | FileCheck %s
 
 // PR1513
 
-// AArch64 ABI actually requires the reverse of what this is testing: the callee
-// does any extensions and remaining bits are unspecified.
-
-// X86_64 ABI does expect extensions for type smaller than 64bits.
-
-// Technically this test wasn't written to test that feature, but it's a
-// valuable check nevertheless.
+// The triple here is chosen so that the struct is passed in two arguments,
+// and the signed char requires sign extension.
 
 struct s{
 long a;

>From b8a3a2eb7c57fae139ee38c37aaaa3750a4acb16 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Thu, 29 Oct 2026 12:09:48 +0100
Subject: [PATCH 11/11] Use consistent terminology on the MLIR side

Always use "conservative" rather than "call-site only". What
conservative is really about is that the sender extends and the
receiver does not assume. For arguments (the only case we currently
care about) this is the same as "extend on call-site only". But
we should represent this consistently everywhere.
---
 clang/include/clang/CodeGen/CGFunctionInfo.h   |  5 +++--
 .../Transforms/CallConvLoweringPass.cpp        |  7 ++-----
 .../TargetLowering/CIRABIRewriteContext.cpp    | 18 ++++++++----------
 llvm/include/llvm/ABI/FunctionInfo.h           |  5 +++--
 mlir/include/mlir/ABI/ABIRewriteContext.h      | 15 ++++++++-------
 5 files changed, 24 insertions(+), 26 deletions(-)

diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h
index bbb96bea04dc76..b3f3fa9d7070f7 100644
--- a/clang/include/clang/CodeGen/CGFunctionInfo.h
+++ b/clang/include/clang/CodeGen/CGFunctionInfo.h
@@ -394,8 +394,9 @@ class ABIArgInfo {
     return !SignExt && !ZeroExt;
   }
 
-  /// Whether the extension is conservative, i.e. the caller should extend, but
-  /// the callee not assume the extension. Only supported for arguments.
+  /// Whether the extension is conservative, i.e. the sender extends, but the
+  /// receiver does not assume the extension. Currently only supported for
+  /// arguments, i.e. caller extends, but callee does not assume extension.
   bool isConservative() const {
     assert(isExtend() && "Invalid kind");
     return Conservative;
diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
index ed12322a4c6bba..208cb1e640e6ad 100644
--- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
@@ -671,18 +671,15 @@ convertABIArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx,
   }
   // An extended value is always read from byte 0 of its own storage, so
   // there is no offset to honor here.
-  // A conservative extension is performed by the caller, but the callee does
-  // not get to assume it, so its attribute only goes on call sites.
   if (info.isExtend()) {
-    bool onCallSiteOnly = info.isConservative();
     if (isa_and_present<cir::BoolType>(origTy))
       return ArgClassification::getExtend(nullptr, info.isSignExt(),
-                                          onCallSiteOnly);
+                                          info.isConservative());
     assert((!origTy || isa<cir::IntType>(origTy)) &&
            "the x86_64 classifier only returns Extend for integers and bool");
     mlir::Type extendedTy = abiTypeToCIR(info.getCoerceToType(), ctx);
     return ArgClassification::getExtend(extendedTy, info.isSignExt(),
-                                        onCallSiteOnly);
+                                        info.isConservative());
   }
   // ArgClassification has no address space for the indirect pointer yet.
   if (info.isIndirectAliased() ||
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
index 0a6c83d6f5ae42..a12e6769ce715a 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRABIRewriteContext.cpp
@@ -212,14 +212,13 @@ static bool needsArgAttrUpdate(const FunctionClassification &fc) {
 }
 
 /// Build an updated arg_attrs ArrayAttr that drops Ignore'd args, adds
-/// llvm.signext / llvm.zeroext on Extend args (only on call sites, as given by
-/// \p isCallSite, if the extension is not assumed by the callee), adds the
-/// pointer attributes for Indirect args in place of llvm.nofpclass, drops
-/// llvm.noundef from a coerced Direct arg that passes undefined bits, gives
-/// each field of a Direct+canFlatten argument the argument's attributes, and
-/// gives each field of an Expand argument an empty dict.  Direct and Extend
-/// slots keep their other existing attributes.  \p origArgTypes provides the
-/// pre-rewrite type for each arg slot.
+/// llvm.signext / llvm.zeroext on Extend args, adds the pointer attributes
+/// for Indirect args in place of llvm.nofpclass, drops llvm.noundef from a
+/// coerced Direct arg that passes undefined bits, gives each field of a
+/// Direct+canFlatten argument the argument's attributes, and gives each field
+/// of an Expand argument an empty dict.  Direct and Extend slots keep their
+/// other existing attributes.  \p origArgTypes provides the pre-rewrite type
+/// for each arg slot.
 mlir::ArrayAttr updateArgAttrs(mlir::MLIRContext *ctx, mlir::ModuleOp module,
                                ArrayRef<mlir::Type> origArgTypes,
                                mlir::ArrayAttr existingArgAttrs,
@@ -249,8 +248,7 @@ mlir::ArrayAttr updateArgAttrs(mlir::MLIRContext *ctx, mlir::ModuleOp module,
       // fields, so each field gets an empty dict.
       auto recTy = cast<cir::RecordType>(origArgTypes[oldIdx]);
       newArgAttrs.append(recTy.getNumElements(), builder.getDictionaryAttr({}));
-    } else if (ac.kind == ArgKind::Extend &&
-               (isCallSite || !ac.extendOnCallSiteOnly)) {
+    } else if (ac.kind == ArgKind::Extend && (isCallSite || !ac.conservative)) {
       StringRef attrName = ac.signExtend
                                ? mlir::LLVM::LLVMDialect::getSExtAttrName()
                                : mlir::LLVM::LLVMDialect::getZExtAttrName();
diff --git a/llvm/include/llvm/ABI/FunctionInfo.h b/llvm/include/llvm/ABI/FunctionInfo.h
index 24c50c204cb78d..ea145a0ff0d482 100644
--- a/llvm/include/llvm/ABI/FunctionInfo.h
+++ b/llvm/include/llvm/ABI/FunctionInfo.h
@@ -275,8 +275,9 @@ class ArgInfo {
     return !SignExt && !ZeroExt;
   }
 
-  /// Whether the extension is conservative, i.e. the caller should extend, but
-  /// the callee not assume the extension. Only supported for arguments.
+  /// Whether the extension is conservative, i.e. the sender extends, but the
+  /// receiver does not assume the extension. Currently only supported for
+  /// arguments, i.e. caller extends, but callee does not assume extension.
   bool isConservative() const {
     assert(isExtend() && "Invalid Kind!");
     return Conservative;
diff --git a/mlir/include/mlir/ABI/ABIRewriteContext.h b/mlir/include/mlir/ABI/ABIRewriteContext.h
index 610250ebc01cf2..868d4535f521bf 100644
--- a/mlir/include/mlir/ABI/ABIRewriteContext.h
+++ b/mlir/include/mlir/ABI/ABIRewriteContext.h
@@ -70,10 +70,11 @@ struct ArgClassification {
   /// For Extend: whether to sign-extend (true) or zero-extend (false).
   bool signExtend = false;
 
-  /// For Extend: whether the extension attribute is only added on call sites.
-  /// The caller performs the extension, but the callee does not get to assume
-  /// that it did.
-  bool extendOnCallSiteOnly = false;
+  /// For Extend: Whether the extension is conservative, i.e. the sender
+  /// extends, but the receiver does not assume the extension. Currently only
+  /// supported for arguments, i.e. caller extends, but callee does not assume
+  /// extension.
+  bool conservative = false;
 
   /// For Direct: whether a struct coercion can be flattened into
   /// individual register-width arguments.
@@ -109,7 +110,7 @@ struct ArgClassification {
     return kind == other.kind && coercedType == other.coercedType &&
            indirectAlign == other.indirectAlign &&
            signExtend == other.signExtend &&
-           extendOnCallSiteOnly == other.extendOnCallSiteOnly &&
+           conservative == other.conservative &&
            canFlatten == other.canFlatten && byVal == other.byVal &&
            indirectAddrSpace == other.indirectAddrSpace &&
            directOffset == other.directOffset &&
@@ -150,12 +151,12 @@ struct ArgClassification {
   }
 
   static ArgClassification getExtend(Type coerced, bool signExt,
-                                     bool onCallSiteOnly = false) {
+                                     bool conservative = false) {
     ArgClassification c;
     c.kind = ArgKind::Extend;
     c.coercedType = coerced;
     c.signExtend = signExt;
-    c.extendOnCallSiteOnly = onCallSiteOnly;
+    c.conservative = conservative;
     return c;
   }
 };



More information about the Mlir-commits mailing list