[clang] [AArch64][msvc] allow higher align than slot size in va_arg (PR #207591)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 5 09:37:54 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: Folkert de Vries (folkertdev)
<details>
<summary>Changes</summary>
Fixes https://github.com/llvm/llvm-project/issues/207584
On aarch64 windows, an `__int128` argument is passed with alignment 16, but was read with an alignment of 8. Based on the MSVC assembly and how e.g. aarch64 darwin handles this, I think it's correct to set `AllowHigherAlign = true`.
---
Full diff: https://github.com/llvm/llvm-project/pull/207591.diff
2 Files Affected:
- (modified) clang/lib/CodeGen/Targets/AArch64.cpp (+6-2)
- (modified) clang/test/CodeGen/win64-i128.c (+24)
``````````diff
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index 6df6b581ee137..2d73dd8cc2916 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -1167,6 +1167,7 @@ RValue AArch64ABIInfo::EmitDarwinVAArg(Address VAListAddr, QualType Ty,
RValue AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty, AggValueSlot Slot) const {
+ bool AllowHigherAlign = false;
bool IsIndirect = false;
if (getTarget().getTriple().isWindowsArm64EC()) {
@@ -1175,6 +1176,10 @@ RValue AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
uint64_t Width = getContext().getTypeSize(Ty);
IsIndirect = Width > 64 || !llvm::isPowerOf2_64(Width);
} else {
+ // E.g. __int128 when passed is aligned to 16 bytes, so it must be read
+ // with the same alignment.
+ AllowHigherAlign = true;
+
// Composites larger than 16 bytes are passed by reference.
if (isAggregateTypeForABI(Ty) && getContext().getTypeSize(Ty) > 128)
IsIndirect = true;
@@ -1182,8 +1187,7 @@ RValue AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
CGF.getContext().getTypeInfoInChars(Ty),
- CharUnits::fromQuantity(8),
- /*allowHigherAlign*/ false, Slot);
+ CharUnits::fromQuantity(8), AllowHigherAlign, Slot);
}
static bool isStreamingCompatible(const FunctionDecl *F) {
diff --git a/clang/test/CodeGen/win64-i128.c b/clang/test/CodeGen/win64-i128.c
index 5095d11a4c81f..6329d5004bcb5 100644
--- a/clang/test/CodeGen/win64-i128.c
+++ b/clang/test/CodeGen/win64-i128.c
@@ -2,6 +2,10 @@
// RUN: | FileCheck %s --check-prefix=GNU64
// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -o - %s \
// RUN: | FileCheck %s --check-prefix=MSC64
+// RUN: %clang_cc1 -triple aarch64-windows-msvc -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=ARM64
+// RUN: %clang_cc1 -triple arm64ec-windows-msvc -emit-llvm -o - %s \
+// RUN: | FileCheck %s --check-prefix=ARM64EC
typedef int int128_t __attribute__((mode(TI)));
@@ -9,21 +13,41 @@ int128_t foo(void) { return 0; }
// GNU64: define dso_local <2 x i64> @foo()
// MSC64: define dso_local <2 x i64> @foo()
+// ARM64: define dso_local i128 @foo()
+// ARM64EC: define dso_local i128 @foo()
int128_t bar(int128_t a, int128_t b) { return a * b; }
// GNU64: define dso_local <2 x i64> @bar(ptr noundef align 16 dead_on_return %0, ptr noundef align 16 dead_on_return %1)
// MSC64: define dso_local <2 x i64> @bar(ptr noundef align 16 dead_on_return %0, ptr noundef align 16 dead_on_return %1)
+// ARM64: define dso_local i128 @bar(i128 noundef %a, i128 noundef %b)
+// ARM64EC: define dso_local i128 @bar(i128 noundef %a, i128 noundef %b)
void vararg(int a, ...) {
// GNU64-LABEL: define{{.*}} void @vararg
// MSC64-LABEL: define{{.*}} void @vararg
+ // ARM64-LABEL: define{{.*}} void @vararg
+ // ARM64EC-LABEL: define{{.*}} void @vararg
__builtin_va_list ap;
__builtin_va_start(ap, a);
int128_t i = __builtin_va_arg(ap, int128_t);
// GNU64: load ptr, ptr
// GNU64: load i128, ptr
+
// MSC64: load ptr, ptr
// MSC64: load i128, ptr
+
+ // Explicitly check that the read is properly aligned.
+ //
+ // ARM64: %argp.cur = load ptr, ptr %ap
+ // ARM64: %argp.cur.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %{{.*}}, i64 -16)
+ // ARM64: load i128, ptr %argp.cur.aligned, align 16
+
+ // On ARM64EC __int128 is passed indirectly, so there is a double load.
+ //
+ // ARM64EC: %argp.cur = load ptr, ptr %ap
+ // ARM64EC: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i64 8
+ // ARM64EC: [[P:%.*]] = load ptr, ptr %argp.cur
+ // ARM64EC: load i128, ptr [[P]], align 16
__builtin_va_end(ap);
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/207591
More information about the cfe-commits
mailing list