Options.NoNaNsFPMath = LangOpts.NoHonorNaNs;
Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
Options.UnsafeFPMath = LangOpts.UnsafeFPMath;
- Options.StackAlignmentOverride = CodeGenOpts.StackAlignment;
Options.BBSections =
llvm::StringSwitch<llvm::BasicBlockSection>(CodeGenOpts.BBSections)
if (getCodeGenOpts().StackProtectorGuardOffset != INT_MAX)
getModule().setStackProtectorGuardOffset(
getCodeGenOpts().StackProtectorGuardOffset);
+ if (getCodeGenOpts().StackAlignment)
+ getModule().setOverrideStackAlignment(getCodeGenOpts().StackAlignment);
getTargetCodeGenInfo().emitTargetMetadata(*this, MangledDeclNames);
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - -mstack-alignment=64 %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s --check-prefix=DEFAULT
// CHECK-LABEL: define{{.*}} void @other()
// CHECK: [[OTHER:#[0-9]+]]
// CHECK-NOT: "stackrealign"
// CHECK: }
// CHECK: attributes [[MAIN]] = { noinline nounwind optnone {{.*}}"stackrealign"{{.*}} }
+// CHECK: !{i32 1, !"override-stack-alignment", i32 64}
+// DEFAULT-NOT: "override-stack-alignment"
int getStackProtectorGuardOffset() const;
void setStackProtectorGuardOffset(int Offset);
+ /// Get/set the stack alignment overridden from the default.
+ unsigned getOverrideStackAlignment() const;
+ void setOverrideStackAlignment(unsigned Align);
+
/// @name Utility functions for querying and setting the build SDK version
/// @{
/// as their parent function, etc.), using an alternate ABI if necessary.
unsigned GuaranteedTailCallOpt : 1;
- /// StackAlignmentOverride - Override default stack alignment for target.
- unsigned StackAlignmentOverride = 0;
-
/// StackSymbolOrdering - When true, this will allow CodeGen to order
/// the local stack symbols (for code size, code locality, or any other
/// heuristics). When false, the local symbols are left in whatever order
CGOPT(bool, EnableGuaranteedTailCallOpt)
CGOPT(bool, DisableTailCalls)
CGOPT(bool, StackSymbolOrdering)
-CGOPT(unsigned, OverrideStackAlignment)
CGOPT(bool, StackRealign)
CGOPT(std::string, TrapFuncName)
CGOPT(bool, UseCtors)
cl::init(true));
CGBINDOPT(StackSymbolOrdering);
- static cl::opt<unsigned> OverrideStackAlignment(
- "stack-alignment", cl::desc("Override default stack alignment"),
- cl::init(0));
- CGBINDOPT(OverrideStackAlignment);
-
static cl::opt<bool> StackRealign(
"stackrealign",
cl::desc("Force align the stack to the minimum alignment"),
Options.EnableAIXExtendedAltivecABI = getEnableAIXExtendedAltivecABI();
Options.NoZerosInBSS = getDontPlaceZerosInBSS();
Options.GuaranteedTailCallOpt = getEnableGuaranteedTailCallOpt();
- Options.StackAlignmentOverride = getOverrideStackAlignment();
Options.StackSymbolOrdering = getStackSymbolOrdering();
Options.UseInitArray = !getUseCtors();
Options.RelaxELFRelocations = getRelaxELFRelocations();
addModuleFlag(ModFlagBehavior::Error, "stack-protector-guard-offset", Offset);
}
+unsigned Module::getOverrideStackAlignment() const {
+ Metadata *MD = getModuleFlag("override-stack-alignment");
+ if (auto *CI = mdconst::dyn_extract_or_null<ConstantInt>(MD))
+ return CI->getZExtValue();
+ return 0;
+}
+
+void Module::setOverrideStackAlignment(unsigned Align) {
+ addModuleFlag(ModFlagBehavior::Error, "override-stack-alignment", Align);
+}
+
void Module::setSDKVersion(const VersionTuple &V) {
SmallVector<unsigned, 3> Entries;
Entries.push_back(V.getMajor());
resetTargetOptions(F);
I = std::make_unique<X86Subtarget>(
TargetTriple, CPU, TuneCPU, FS, *this,
- MaybeAlign(Options.StackAlignmentOverride), PreferVectorWidthOverride,
- RequiredVectorWidth);
+ MaybeAlign(F.getParent()->getOverrideStackAlignment()),
+ PreferVectorWidthOverride, RequiredVectorWidth);
}
return I.get();
}
; Check that stack alignment can be forced. Individual targets should test their
; specific implementation details.
-; RUN: llc < %s -stackrealign -stack-alignment=32 | FileCheck %s
+; RUN: llc < %s -stackrealign | FileCheck %s
; CHECK-LABEL: @f
; CHECK-LABEL: @g
}
declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i1) nounwind
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"override-stack-alignment", i32 32}
-; RUN: llc -mtriple=x86_64-apple-macosx -mattr=+cx16 -x86-use-base-pointer=true -stackrealign -stack-alignment=32 %s -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE --check-prefix=USE_BASE_64 %s
-; RUN: llc -mtriple=x86_64-apple-macosx -mattr=+cx16 -x86-use-base-pointer=false -stackrealign -stack-alignment=32 %s -o - | FileCheck --check-prefix=CHECK --check-prefix=DONT_USE_BASE %s
-; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+cx16 -x86-use-base-pointer=true -stackrealign -stack-alignment=32 %s -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE --check-prefix=USE_BASE_32 %s
-; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+cx16 -x86-use-base-pointer=false -stackrealign -stack-alignment=32 %s -o - | FileCheck --check-prefix=CHECK --check-prefix=DONT_USE_BASE %s
+; RUN: llc -mtriple=x86_64-apple-macosx -mattr=+cx16 -x86-use-base-pointer=true -stackrealign %s -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE --check-prefix=USE_BASE_64 %s
+; RUN: llc -mtriple=x86_64-apple-macosx -mattr=+cx16 -x86-use-base-pointer=false -stackrealign %s -o - | FileCheck --check-prefix=CHECK --check-prefix=DONT_USE_BASE %s
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+cx16 -x86-use-base-pointer=true -stackrealign %s -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE --check-prefix=USE_BASE_32 %s
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+cx16 -x86-use-base-pointer=false -stackrealign %s -o - | FileCheck --check-prefix=CHECK --check-prefix=DONT_USE_BASE %s
; This function uses dynamic allocated stack to force the use
; of a frame pointer.
store i32 %n, i32* %idx
ret i1 %res
}
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"override-stack-alignment", i32 32}
-; RUN: llc -mtriple=x86_64-pc-linux-gnu -mattr=+mwaitx -x86-use-base-pointer=true -stackrealign -stack-alignment=32 %s -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE_64 %s
-; RUN: llc -mtriple=x86_64-pc-linux-gnux32 -mattr=+mwaitx -x86-use-base-pointer=true -stackrealign -stack-alignment=32 %s -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE_32 %s
-; RUN: llc -mtriple=x86_64-pc-linux-gnu -mattr=+mwaitx -x86-use-base-pointer=true %s -o - | FileCheck --check-prefix=CHECK --check-prefix=NO_BASE_64 %s
-; RUN: llc -mtriple=x86_64-pc-linux-gnux32 -mattr=+mwaitx -x86-use-base-pointer=true %s -o - | FileCheck --check-prefix=CHECK --check-prefix=NO_BASE_32 %s
+; RUN: split-file %s %t
+; RUN: cat %t/main.ll %t/_align32.ll > %t/align32.ll
+; RUN: llc -mtriple=x86_64-pc-linux-gnu -mattr=+mwaitx -x86-use-base-pointer=true -stackrealign %t/align32.ll -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE_64 %s
+; RUN: llc -mtriple=x86_64-pc-linux-gnux32 -mattr=+mwaitx -x86-use-base-pointer=true -stackrealign %t/align32.ll -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE_32 %s
+; RUN: llc -mtriple=x86_64-pc-linux-gnu -mattr=+mwaitx -x86-use-base-pointer=true %t/main.ll -o - | FileCheck --check-prefix=CHECK --check-prefix=NO_BASE_64 %s
+; RUN: llc -mtriple=x86_64-pc-linux-gnux32 -mattr=+mwaitx -x86-use-base-pointer=true %t/main.ll -o - | FileCheck --check-prefix=CHECK --check-prefix=NO_BASE_32 %s
+
+;--- main.ll
; This test checks that we save and restore the base pointer (ebx or rbx) in the
; presence of the mwaitx intrinsic which requires to use ebx for one of its
; NO_BASE_32-NEXT: {{.+$}}
declare void @llvm.x86.mwaitx(i32, i32, i32) nounwind
+;--- _align32.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"override-stack-alignment", i32 32}
--- /dev/null
+; RUN: llc < %s -stack-symbol-ordering=0 -mcpu=generic -stackrealign -mattr=+avx -mtriple=x86_64-apple-darwin10 | FileCheck %s
+; rdar://11496434
+declare void @t1_helper(i32*)
+declare void @t3_helper(i32*, i32*)
+
+; Test when forcing stack alignment
+define i32 @t8() nounwind uwtable {
+entry:
+ %a = alloca i32, align 4
+ call void @t1_helper(i32* %a) nounwind
+ %0 = load i32, i32* %a, align 4
+ %add = add nsw i32 %0, 13
+ ret i32 %add
+
+; CHECK: _t8
+; CHECK: movq %rsp, %rbp
+; CHECK: andq $-32, %rsp
+; CHECK-NEXT: subq $32, %rsp
+; CHECK: movq %rbp, %rsp
+; CHECK: popq %rbp
+}
+
+; VLAs
+define i32 @t9(i64 %sz) nounwind uwtable {
+entry:
+ %a = alloca i32, align 4
+ %vla = alloca i32, i64 %sz, align 16
+ call void @t3_helper(i32* %a, i32* %vla) nounwind
+ %0 = load i32, i32* %a, align 4
+ %add = add nsw i32 %0, 13
+ ret i32 %add
+
+; CHECK: _t9
+; CHECK: pushq %rbp
+; CHECK: movq %rsp, %rbp
+; CHECK: pushq %rbx
+; CHECK: andq $-32, %rsp
+; CHECK: subq $32, %rsp
+; CHECK: movq %rsp, %rbx
+
+; CHECK: leaq -8(%rbp), %rsp
+; CHECK: popq %rbx
+; CHECK: popq %rbp
+}
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"override-stack-alignment", i32 32}
; RUN: llc < %s -stack-symbol-ordering=0 -mcpu=generic -mattr=+avx -mtriple=x86_64-apple-darwin10 | FileCheck %s
-; RUN: llc < %s -stack-symbol-ordering=0 -mcpu=generic -stackrealign -stack-alignment=32 -mattr=+avx -mtriple=x86_64-apple-darwin10 | FileCheck %s -check-prefix=FORCE-ALIGN
; rdar://11496434
; no VLAs or dynamic alignment
declare void @bar(i32, i32*, %struct.struct_t* byval(%struct.struct_t) align 8)
declare void @llvm.stackrestore(i8*) nounwind
-
-
-; Test when forcing stack alignment
-define i32 @t8() nounwind uwtable {
-entry:
- %a = alloca i32, align 4
- call void @t1_helper(i32* %a) nounwind
- %0 = load i32, i32* %a, align 4
- %add = add nsw i32 %0, 13
- ret i32 %add
-
-; FORCE-ALIGN: _t8
-; FORCE-ALIGN: movq %rsp, %rbp
-; FORCE-ALIGN: andq $-32, %rsp
-; FORCE-ALIGN-NEXT: subq $32, %rsp
-; FORCE-ALIGN: movq %rbp, %rsp
-; FORCE-ALIGN: popq %rbp
-}
-
-; VLAs
-define i32 @t9(i64 %sz) nounwind uwtable {
-entry:
- %a = alloca i32, align 4
- %vla = alloca i32, i64 %sz, align 16
- call void @t3_helper(i32* %a, i32* %vla) nounwind
- %0 = load i32, i32* %a, align 4
- %add = add nsw i32 %0, 13
- ret i32 %add
-
-; FORCE-ALIGN: _t9
-; FORCE-ALIGN: pushq %rbp
-; FORCE-ALIGN: movq %rsp, %rbp
-; FORCE-ALIGN: pushq %rbx
-; FORCE-ALIGN: andq $-32, %rsp
-; FORCE-ALIGN: subq $32, %rsp
-; FORCE-ALIGN: movq %rsp, %rbx
-
-; FORCE-ALIGN: leaq -8(%rbp), %rsp
-; FORCE-ALIGN: popq %rbx
-; FORCE-ALIGN: popq %rbp
-}
; arbitrarily force alignment up to 32-bytes for i386 hoping that this will
; exceed any ABI provisions.
;
-; RUN: llc < %s -mcpu=generic -stackrealign -stack-alignment=32 | FileCheck %s
+; RUN: llc < %s -mcpu=generic -stackrealign | FileCheck %s
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
target triple = "i386-unknown-linux-gnu"
}
declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i1) nounwind
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"override-stack-alignment", i32 32}
-; RUN: llc < %s -stack-symbol-ordering=0 -tailcallopt -code-model=medium -stack-alignment=4 -mtriple=i686-linux-gnu -mcpu=pentium | FileCheck %s
+; RUN: llc < %s -stack-symbol-ordering=0 -tailcallopt -code-model=medium -mtriple=i686-linux-gnu -mcpu=pentium | FileCheck %s
; Check the HiPE calling convention works (x86-32)
@clos = external dso_local constant i32
declare cc 11 void @bar(i32, i32, i32, i32, i32)
declare cc 11 { i32, i32, i32 } @tailcallee(i32, i32, i32, i32, i32, i32)
+
+!llvm.module.flags = !{!3}
+!3 = !{i32 2, !"override-stack-alignment", i32 4}
-; RUN: llc < %s -stack-symbol-ordering=0 -tailcallopt -relocation-model=static -code-model=medium -stack-alignment=8 -mtriple=x86_64-linux-gnu -mcpu=opteron | FileCheck %s
+; RUN: llc < %s -stack-symbol-ordering=0 -tailcallopt -relocation-model=static -code-model=medium -mtriple=x86_64-linux-gnu -mcpu=opteron | FileCheck %s
; Check the HiPE calling convention works (x86-64)
@clos = external constant i64
declare cc 11 void @bar(i64, i64, i64, i64, i64, i64)
declare cc 11 { i64, i64, i64 } @tailcallee(i64, i64, i64, i64, i64, i64, i64)
+!llvm.module.flags = !{!3}
+!3 = !{i32 2, !"override-stack-alignment", i32 8}
--- /dev/null
+; RUN: llc < %s -mtriple=i686-windows -stackrealign | FileCheck %s
+
+declare void @good(i32 %a, i32 %b, i32 %c, i32 %d)
+declare void @oneparam(i32 %a)
+declare void @eightparams(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h)
+
+; When there is no reserved call frame, check that additional alignment
+; is added when the pushes don't add up to the required alignment.
+; CHECK-LABEL: test5:
+; CHECK: subl $16, %esp
+; CHECK-NEXT: pushl $4
+; CHECK-NEXT: pushl $3
+; CHECK-NEXT: pushl $2
+; CHECK-NEXT: pushl $1
+; CHECK-NEXT: call
+define void @test5(i32 %k) {
+entry:
+ %a = alloca i32, i32 %k
+ call void @good(i32 1, i32 2, i32 3, i32 4)
+ ret void
+}
+
+; When the alignment adds up, do the transformation
+; CHECK-LABEL: test5b:
+; CHECK: pushl $8
+; CHECK-NEXT: pushl $7
+; CHECK-NEXT: pushl $6
+; CHECK-NEXT: pushl $5
+; CHECK-NEXT: pushl $4
+; CHECK-NEXT: pushl $3
+; CHECK-NEXT: pushl $2
+; CHECK-NEXT: pushl $1
+; CHECK-NEXT: call
+define void @test5b() optsize {
+entry:
+ call void @eightparams(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8)
+ ret void
+}
+
+; When having to compensate for the alignment isn't worth it,
+; don't use pushes.
+; CHECK-LABEL: test5c:
+; CHECK: movl $1, (%esp)
+; CHECK-NEXT: call
+define void @test5c() optsize {
+entry:
+ call void @oneparam(i32 1)
+ ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"override-stack-alignment", i32 32}
; RUN: llc < %s -mtriple=i686-windows | FileCheck %s -check-prefix=NORMAL
; RUN: llc < %s -mtriple=i686-windows -no-x86-call-frame-opt | FileCheck %s -check-prefix=NOPUSH
; RUN: llc < %s -mtriple=x86_64-windows | FileCheck %s -check-prefix=X64
-; RUN: llc < %s -mtriple=i686-windows -stackrealign -stack-alignment=32 | FileCheck %s -check-prefix=ALIGNED
; RUN: llc < %s -mtriple=i686-pc-linux | FileCheck %s -check-prefix=LINUX
%class.Class = type { i32 }
ret void
}
-; When there is no reserved call frame, check that additional alignment
-; is added when the pushes don't add up to the required alignment.
-; ALIGNED-LABEL: test5:
-; ALIGNED: subl $16, %esp
-; ALIGNED-NEXT: pushl $4
-; ALIGNED-NEXT: pushl $3
-; ALIGNED-NEXT: pushl $2
-; ALIGNED-NEXT: pushl $1
-; ALIGNED-NEXT: call
-define void @test5(i32 %k) {
-entry:
- %a = alloca i32, i32 %k
- call void @good(i32 1, i32 2, i32 3, i32 4)
- ret void
-}
-
-; When the alignment adds up, do the transformation
-; ALIGNED-LABEL: test5b:
-; ALIGNED: pushl $8
-; ALIGNED-NEXT: pushl $7
-; ALIGNED-NEXT: pushl $6
-; ALIGNED-NEXT: pushl $5
-; ALIGNED-NEXT: pushl $4
-; ALIGNED-NEXT: pushl $3
-; ALIGNED-NEXT: pushl $2
-; ALIGNED-NEXT: pushl $1
-; ALIGNED-NEXT: call
-define void @test5b() optsize {
-entry:
- call void @eightparams(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8)
- ret void
-}
-
-; When having to compensate for the alignment isn't worth it,
-; don't use pushes.
-; ALIGNED-LABEL: test5c:
-; ALIGNED: movl $1, (%esp)
-; ALIGNED-NEXT: call
-define void @test5c() optsize {
-entry:
- call void @oneparam(i32 1)
- ret void
-}
-
; Check that pushing the addresses of globals (Or generally, things that
; aren't exactly immediates) isn't broken.
; Fixes PR21878.
-; RUN: llc < %s -stackrealign -stack-alignment=32 -mattr=+avx -mtriple=x86_64-apple-darwin10 | FileCheck %s
+; RUN: llc < %s -stackrealign -mattr=+avx -mtriple=x86_64-apple-darwin10 | FileCheck %s
; PR11468
define void @f(i64 %sz) uwtable {
; CHECK: popq %rbp
}
+!llvm.module.flags = !{!1}
!0 = !{i32 125}
-
+!1 = !{i32 2, !"override-stack-alignment", i32 32}
-; RUN: llc -mtriple=i386-unknown-freebsd -mcpu=core2 -stack-alignment=4 -relocation-model=pic < %s | FileCheck %s -check-prefix=UNALIGNED
-; RUN: llc -mtriple=i386-unknown-freebsd -mcpu=core2 -stack-alignment=16 -relocation-model=pic < %s | FileCheck %s -check-prefix=ALIGNED
-; RUN: llc -mtriple=i386-unknown-freebsd -mcpu=core2 -stack-alignment=4 -stackrealign -relocation-model=pic < %s | FileCheck %s -check-prefix=FORCEALIGNED
+; RUN: split-file %s %t
+; RUN: cat %t/main.ll %t/align4.ll > %t/a2.ll
+; RUN: cat %t/main.ll %t/align16.ll > %t/b2.ll
+; RUN: llc -mtriple=i386-unknown-freebsd -mcpu=core2 -relocation-model=pic < %t/a2.ll | FileCheck %s -check-prefix=UNALIGNED
+; RUN: llc -mtriple=i386-unknown-freebsd -mcpu=core2 -relocation-model=pic < %t/b2.ll | FileCheck %s -check-prefix=ALIGNED
+; RUN: llc -mtriple=i386-unknown-freebsd -mcpu=core2 -stackrealign -relocation-model=pic < %t/a2.ll | FileCheck %s -check-prefix=FORCEALIGNED
+;--- main.ll
@arr = internal unnamed_addr global [32 x i32] zeroinitializer, align 16
; PR12250
; FORCEALIGNED: movdqa {{.*}} # 16-byte Spill
; FORCEALIGNED: paddd {{.*}} # 16-byte Folded Reload
}
+!llvm.module.flags = !{!0}
+;--- align4.ll
+!0 = !{i32 2, !"override-stack-alignment", i32 4}
+;--- align16.ll
+!0 = !{i32 2, !"override-stack-alignment", i32 16}
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=x86_64-pc-linux -stackrealign -stack-alignment=32 < %s | FileCheck %s
-; RUN: llc -mtriple=x86_64-pc-linux-gnux32 -stackrealign -stack-alignment=32 < %s | FileCheck -check-prefix=X32ABI %s
+; RUN: llc -mtriple=x86_64-pc-linux -stackrealign < %s | FileCheck %s
+; RUN: llc -mtriple=x86_64-pc-linux-gnux32 -stackrealign < %s | FileCheck -check-prefix=X32ABI %s
; This should run with NaCl as well ( -mtriple=x86_64-pc-nacl ) but currently doesn't due to PR22655
}
attributes #0 = { nounwind "frame-pointer"="all"}
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"override-stack-alignment", i32 32}
; elements (here: XMM spills) are accessed using instructions that tolerate
; unaligned access.
;
-; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64 -mattr=+sse,+sse-unaligned-mem -stack-alignment=8 --frame-pointer=all < %s | FileCheck %s
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64 -mattr=+sse,+sse-unaligned-mem --frame-pointer=all < %s | FileCheck %s
define dso_local preserve_allcc void @func() #0 {
; CHECK-LABEL: func:
}
attributes #0 = { nounwind }
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"override-stack-alignment", i32 8}
--- /dev/null
+; RUN: split-file %s %t
+; RUN: llvm-link %t/main.ll %t/8.ll
+; RUN: not llvm-link %t/main.ll %t/16.ll 2>&1 | FileCheck --check-prefix=CHECK-16 %s
+
+;--- main.ll
+; NONE: error: linking module flags 'override-stack-alignment': IDs have conflicting values
+; CHECK-16: error: linking module flags 'override-stack-alignment': IDs have conflicting values
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"override-stack-alignment", i32 8}
+;--- 8.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"override-stack-alignment", i32 8}
+;--- 16.ll
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"override-stack-alignment", i32 16}