diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1918,7 +1918,8 @@ A function with the ``ssp`` attribute but without the ``alwaysinline`` attribute cannot be inlined into a function without a ``ssp/sspreq/sspstrong`` attribute. If inlined, the caller will get the - ``ssp`` attribute. + ``ssp`` attribute. ``call``, ``invoke``, and ``callbr`` instructions with + the ``alwaysinline`` attribute force inlining. ``sspstrong`` This attribute indicates that the function should emit a stack smashing protector. This attribute causes a strong heuristic to be used when @@ -1946,7 +1947,9 @@ A function with the ``sspstrong`` attribute but without the ``alwaysinline`` attribute cannot be inlined into a function without a ``ssp/sspstrong/sspreq`` attribute. If inlined, the caller will get the - ``sspstrong`` attribute unless the ``sspreq`` attribute exists. + ``sspstrong`` attribute unless the ``sspreq`` attribute exists. ``call``, + ``invoke``, and ``callbr`` instructions with the ``alwaysinline`` attribute + force inlining. ``sspreq`` This attribute indicates that the function should *always* emit a stack smashing protector. This overrides the ``ssp`` and ``sspstrong`` function @@ -1966,7 +1969,8 @@ A function with the ``sspreq`` attribute but without the ``alwaysinline`` attribute cannot be inlined into a function without a ``ssp/sspstrong/sspreq`` attribute. If inlined, the caller will get the - ``sspreq`` attribute. + ``sspreq`` attribute. ``call``, ``invoke``, and ``callbr`` instructions + with the ``alwaysinline`` attribute force inlining. ``strictfp`` This attribute indicates that the function was called from a scope that diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -2159,16 +2159,6 @@ /// If the inlined function had a higher stack protection level than the /// calling function, then bump up the caller's stack protection level. static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) { -#ifndef NDEBUG - if (!Callee.hasFnAttribute(Attribute::AlwaysInline)) { - assert(!(!Callee.hasStackProtectorFnAttr() && - Caller.hasStackProtectorFnAttr()) && - "stack protected caller but callee requested no stack protector"); - assert(!(!Caller.hasStackProtectorFnAttr() && - Callee.hasStackProtectorFnAttr()) && - "stack protected callee but caller requested no stack protector"); - } -#endif // If upgrading the SSP attribute, clear out the old SSP Attributes first. // Having multiple SSP attributes doesn't actually hurt, but it adds useless // clutter to the IR. diff --git a/llvm/test/Transforms/Inline/inline_nossp.ll b/llvm/test/Transforms/Inline/inline_nossp.ll --- a/llvm/test/Transforms/Inline/inline_nossp.ll +++ b/llvm/test/Transforms/Inline/inline_nossp.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -inline -o - -S %s | FileCheck %s -; RUN: opt -passes='cgscc(inline)' %s -S | FileCheck %s +; RUN: opt -inline -o - -S %s | FileCheck --check-prefixes=CHECK,CHECK-INLINE %s +; RUN: opt -passes='cgscc(inline)' %s -S | FileCheck --check-prefixes=CHECK,CHECK-INLINE %s ; RUN: opt -always-inline -o - -S %s | FileCheck %s ; RUN: opt -passes=always-inline -o - -S %s | FileCheck %s @@ -92,6 +92,31 @@ ret void } +; The alwaysinline attribute can also appear on the CallBase (ie. the call +; site), ie. when __attribute__((flatten)) is used on the caller. Treat this +; the same as if the caller had the fn attr alwaysinline and permit inline +; substitution, despite the mismatch between caller and callee on ssp attrs. +; +; Curiously, the always_inline attribute on a CallInst is only expanded by the +; inline pass, but not always_inline pass! +define void @nossp_alwaysinline_caller() { +; CHECK-LABEL: @nossp_alwaysinline_caller( +; CHECK-INLINE-NEXT: [[TMP1:%.*]] = alloca i64, align 8 +; CHECK-INLINE-NEXT: [[SAVEDSTACK:%.*]] = call i8* @llvm.stacksave() +; CHECK-INLINE-NEXT: [[TMP2:%.*]] = bitcast i64* [[TMP1]] to i8* +; CHECK-INLINE-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[TMP2]]) +; CHECK-INLINE-NEXT: store i64 1024, i64* [[TMP1]], align 8 +; CHECK-INLINE-NEXT: [[TMP3:%.*]] = load i64, i64* [[TMP1]], align 8 +; CHECK-INLINE-NEXT: [[TMP4:%.*]] = alloca i8, i64 [[TMP3]], align 16 +; CHECK-INLINE-NEXT: call void @foo(i8* [[TMP4]]) +; CHECK-INLINE-NEXT: [[TMP5:%.*]] = bitcast i64* [[TMP1]] to i8* +; CHECK-INLINE-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[TMP5]]) +; CHECK-INLINE-NEXT: call void @llvm.stackrestore(i8* [[SAVEDSTACK]]) +; CHECK: ret void + call void @ssp(i64 1024) #2 + ret void +} + attributes #0 = { sspstrong } attributes #1 = { sspstrong alwaysinline } -attributes #2 = { alwaysinline} +attributes #2 = { alwaysinline }