https://github.com/folkertdev created https://github.com/llvm/llvm-project/pull/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 >From 863ff962f5a485df1cfe4d0f173f157d17011852 Mon Sep 17 00:00:00 2001 From: Folkert de Vries <[email protected]> Date: Mon, 3 Aug 2026 10:22:41 +0200 Subject: [PATCH] fix i128 register alignment --- clang/docs/ReleaseNotes.md | 3 ++ clang/lib/CodeGen/Targets/Mips.cpp | 21 ++++++++----- clang/test/CodeGen/mips64-padding-arg.c | 41 +++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index d4b1cf9e44945..3e6397ae5707b 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -85,6 +85,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 c093cfc668c2e..90d1b5e5dcb20 100644 --- a/clang/lib/CodeGen/Targets/Mips.cpp +++ b/clang/lib/CodeGen/Targets/Mips.cpp @@ -49,7 +49,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 { @@ -292,12 +292,19 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { !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* @@ -468,14 +475,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) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
