From 5012f1db20d583a1fc36a334200842eb0b945902 Mon Sep 17 00:00:00 2001 From: "Duncan P. N. Exon Smith" Date: Wed, 20 Aug 2014 19:40:59 +0000 Subject: [PATCH] X86: Align the stack on word boundaries in LowerFormalArguments() The goal of the patch is to implement section 3.2.3 of the AMD64 ABI correctly. The controlling sentence is, "The size of each argument gets rounded up to eightbytes. Therefore the stack will always be eightbyte aligned." The equivalent sentence in the i386 ABI page 37 says, "At all times, the stack pointer should point to a word-aligned area." For both architectures, the stack pointer is not being rounded up to the nearest eightbyte or word between the last normal argument and the first variadic argument. Patch by Thomas Jablin! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216119 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/CallingConvLower.h | 9 ++++++-- lib/Target/X86/X86ISelLowering.cpp | 1 + test/CodeGen/X86/aligned-variadic.ll | 30 +++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 test/CodeGen/X86/aligned-variadic.ll diff --git a/include/llvm/CodeGen/CallingConvLower.h b/include/llvm/CodeGen/CallingConvLower.h index 866b3c8c6bc..ffedd2e1410 100644 --- a/include/llvm/CodeGen/CallingConvLower.h +++ b/include/llvm/CodeGen/CallingConvLower.h @@ -371,11 +371,16 @@ public: return Reg; } + /// AlignStack - Align the top of the stakc to the specified alignment. + void AlignStack(unsigned Align) { + assert(Align && ((Align - 1) & Align) == 0); // Align is power of 2. + StackOffset = ((StackOffset + Align - 1) & ~(Align - 1)); + } + /// AllocateStack - Allocate a chunk of stack space with the specified size /// and alignment. unsigned AllocateStack(unsigned Size, unsigned Align) { - assert(Align && ((Align-1) & Align) == 0); // Align is power of 2. - StackOffset = ((StackOffset + Align-1) & ~(Align-1)); + AlignStack(Align); unsigned Result = StackOffset; StackOffset += Size; MF.getFrameInfo()->ensureMaxAlignment(Align); diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 9cb9e6abbef..a10023df8a0 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -2300,6 +2300,7 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain, CCInfo.AllocateStack(32, 8); CCInfo.AnalyzeFormalArguments(Ins, CC_X86); + CCInfo.AlignStack(Is64Bit ? 8 : 4); unsigned LastVal = ~0U; SDValue ArgValue; diff --git a/test/CodeGen/X86/aligned-variadic.ll b/test/CodeGen/X86/aligned-variadic.ll new file mode 100644 index 00000000000..68000e36bc6 --- /dev/null +++ b/test/CodeGen/X86/aligned-variadic.ll @@ -0,0 +1,30 @@ +; RUN: llc < %s -march=x86-64 | FileCheck %s -check-prefix=X64 +; RUN: llc < %s -march=x86 | FileCheck %s -check-prefix=X32 + +%struct.Baz = type { [17 x i8] } +%struct.__va_list_tag = type { i32, i32, i8*, i8* } + +; Function Attrs: nounwind uwtable +define void @bar(%struct.Baz* byval nocapture readnone align 8 %x, ...) { +entry: + %va = alloca [1 x %struct.__va_list_tag], align 16 + %arraydecay = getelementptr inbounds [1 x %struct.__va_list_tag]* %va, i64 0, i64 0 + %arraydecay1 = bitcast [1 x %struct.__va_list_tag]* %va to i8* + call void @llvm.va_start(i8* %arraydecay1) + %overflow_arg_area_p = getelementptr inbounds [1 x %struct.__va_list_tag]* %va, i64 0, i64 0, i32 2 + %overflow_arg_area = load i8** %overflow_arg_area_p, align 8 + %overflow_arg_area.next = getelementptr i8* %overflow_arg_area, i64 24 + store i8* %overflow_arg_area.next, i8** %overflow_arg_area_p, align 8 +; X32: leal 68(%esp), [[REG:%.*]] +; X32: movl [[REG]], 16(%esp) +; X64: leaq 232(%rsp), [[REG:%.*]] +; X64: movq [[REG]], 184(%rsp) +; X64: leaq 176(%rsp), %rdi + call void @qux(%struct.__va_list_tag* %arraydecay) + ret void +} + +; Function Attrs: nounwind +declare void @llvm.va_start(i8*) + +declare void @qux(%struct.__va_list_tag*)