[clang] a49d906 - [MIPS] fix `__int128` register alignment (#214322)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 20 03:00:32 PDT 2026
Author: Folkert de Vries
Date: 2026-08-20T12:00:26+02:00
New Revision: a49d90627bd44d2e76c20b9d4e0cafb339fb806f
URL: https://github.com/llvm/llvm-project/commit/a49d90627bd44d2e76c20b9d4e0cafb339fb806f
DIFF: https://github.com/llvm/llvm-project/commit/a49d90627bd44d2e76c20b9d4e0cafb339fb806f.diff
LOG: [MIPS] fix `__int128` register alignment (#214322)
fixes https://github.com/llvm/llvm-project/issues/213541
On `mips64` and `mips64el`, an `i128` needs to be register-aligned to an
even-numbered register to be compatible with GCC. Insert padding to make
that true.
GCC applies the additional alignment here:
https://github.com/gcc-mirror/gcc/blob/529304e456c9be38139325e3c2567f7d2a93e7c8/gcc/config/mips/mips.cc#L6210-L6223
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/lib/CodeGen/Targets/Mips.cpp
clang/test/CodeGen/mips64-padding-arg.c
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 0645b4345643b..d1856c4236020 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -93,6 +93,9 @@ features cannot lower the translation-unit ABI level;
always passed the parts separately. `-fclang-abi-compat=23` restores the previous
behavior. (#GH212109)
+- On MIPS N32/N64, an `__int128` now correctly start in an even-numbered register
+ or 16-byte aligned stack slot, matching GCC.
+
### AST Dumping Potentially Breaking Changes
### Clang Frontend Potentially Breaking Changes
diff --git a/clang/lib/CodeGen/Targets/Mips.cpp b/clang/lib/CodeGen/Targets/Mips.cpp
index 6286e309dab22..4ad1a56b92a39 100644
--- a/clang/lib/CodeGen/Targets/Mips.cpp
+++ b/clang/lib/CodeGen/Targets/Mips.cpp
@@ -50,7 +50,7 @@ class MipsABIInfo : public ABIInfo {
void computeInfo(CGFunctionInfo &FI) const override;
RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
AggValueSlot Slot) const override;
- ABIArgInfo extendType(QualType Ty) const;
+ ABIArgInfo extendType(QualType Ty, llvm::Type *Padding = nullptr) const;
};
class MIPSTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -299,12 +299,19 @@ ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset,
!getContext().getTargetInfo().hasInt128Type()))
return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
+ // Scalars never get explicit padding on O32: CC_MipsO32 already does the
+ // alignment itself based on the argument's original alignment.
+ //
+ // For __int128 and other types that are 16-byte aligned this padding ensures
+ // that the value starts in an even-numbered register or stack slot.
+ llvm::Type *Padding =
+ IsO32 ? nullptr : getPaddingType(OrigOffset, CurrOffset);
+
// All integral types are promoted to the GPR width.
if (Ty->isIntegralOrEnumerationType())
- return extendType(Ty);
+ return extendType(Ty, Padding);
- return ABIArgInfo::getDirect(
- nullptr, 0, IsO32 ? nullptr : getPaddingType(OrigOffset, CurrOffset));
+ return ABIArgInfo::getDirect(nullptr, 0, Padding);
}
llvm::Type*
@@ -495,14 +502,14 @@ RValue MipsABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
return Res;
}
-ABIArgInfo MipsABIInfo::extendType(QualType Ty) const {
+ABIArgInfo MipsABIInfo::extendType(QualType Ty, llvm::Type *Padding) const {
int TySize = getContext().getTypeSize(Ty);
// MIPS64 ABI requires unsigned 32 bit integers to be sign extended.
if (Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)
- return ABIArgInfo::getSignExtend(Ty);
+ return ABIArgInfo::getSignExtend(Ty, /*T=*/nullptr, Padding);
- return ABIArgInfo::getExtend(Ty);
+ return ABIArgInfo::getExtend(Ty, /*T=*/nullptr, Padding);
}
bool
diff --git a/clang/test/CodeGen/mips64-padding-arg.c b/clang/test/CodeGen/mips64-padding-arg.c
index bb92a841c3f61..e2078c9294a0b 100644
--- a/clang/test/CodeGen/mips64-padding-arg.c
+++ b/clang/test/CodeGen/mips64-padding-arg.c
@@ -43,6 +43,47 @@ S0 foo5(long double a0) {
return foo6(1, 2, a0);
}
+#ifdef __SIZEOF_INT128__
+// Insert padding before a 128-bit integer argument, which is 16-byte aligned, to make it start in an even-numbered register.
+//
+// N64-LABEL: define{{.*}} void @foo11(i32 noundef signext %a0, i64 %0, i128 noundef signext %a1)
+// N64: tail call void @foo12(i32 noundef signext 1, i32 noundef signext 2, i32 noundef signext %a0, i64 undef, i128 noundef signext %a1)
+// N64: declare void @foo12(i32 noundef signext, i32 noundef signext, i32 noundef signext, i64, i128 noundef signext)
+
+extern void foo12(int, int, int, __int128);
+
+void foo11(int a0, __int128 a1) {
+ foo12(1, 2, a0, a1);
+}
+
+// Do not insert padding if the 128-bit integer is already 16-byte aligned.
+// Hence foo13 needs padding but foo14 does not.
+//
+// N64-LABEL: define{{.*}} void @foo13(i32 noundef signext %a0, i64 %0, i128 noundef zeroext %a1)
+// N64: tail call void @foo14(i32 noundef signext 1, i32 noundef signext %a0, i128 noundef zeroext %a1)
+// N64: declare void @foo14(i32 noundef signext, i32 noundef signext, i128 noundef zeroext)
+
+extern void foo14(int, int, unsigned __int128);
+
+void foo13(int a0, unsigned __int128 a1) {
+ foo14(1, a0, a1);
+}
+
+// Test a case where all but one argument register is exhausted.
+// The padding is still inserted, and the full __int128 value is
+// passed via the stack, it is not split.
+//
+// N64-LABEL: define{{.*}} void @foo15(i64 noundef signext %a0, i64 noundef signext %a1, i64 noundef signext %a2, i64 noundef signext %a3, i64 noundef signext %a4, i64 noundef signext %a5, i64 noundef signext %a6, i64 %0, i128 noundef signext %a7)
+// N64: tail call void @foo16(i64 noundef signext %a0, i64 noundef signext %a1, i64 noundef signext %a2, i64 noundef signext %a3, i64 noundef signext %a4, i64 noundef signext %a5, i64 noundef signext %a6, i64 undef, i128 noundef signext %a7)
+// N64: declare void @foo16(i64 noundef signext, i64 noundef signext, i64 noundef signext, i64 noundef signext, i64 noundef signext, i64 noundef signext, i64 noundef signext, i64, i128 noundef signext)
+
+extern void foo16(long, long, long, long, long, long, long, __int128);
+
+void foo15(long a0, long a1, long a2, long a3, long a4, long a5, long a6, __int128 a7) {
+ foo16(a0, a1, a2, a3, a4, a5, a6, a7);
+}
+#endif
+
// Do not insert padding if ABI is O32.
//
// O32-LABEL: define{{.*}} void @foo7(float noundef %a0, double noundef %a1)
More information about the cfe-commits
mailing list