Skip to content

Commit

Permalink
[llvm][Arm][AArch64] Do not inline a function with different signing …
Browse files Browse the repository at this point in the history
…scheme.

If the signing scheme is different that maybe the functions assumes different behaviours and dangerous to inline them without analysing them.
This should be a rare case.
  • Loading branch information
DanielKristofKiss committed Feb 14, 2024
1 parent 9b80ab4 commit 823a939
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 10 deletions.
14 changes: 12 additions & 2 deletions llvm/include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -342,11 +342,18 @@ def DenormalFPMathF32 : ComplexStrAttr<"denormal-fp-math-f32", [FnAttr]>;
class CompatRule<string F> {
// The name of the function called to check the attribute of the caller and
// callee and decide whether inlining should be allowed. The function's
// signature must match "bool(const Function&, const Function &)", where the
// signature must match "bool(const Function&, const Function&)", where the
// first parameter is the reference to the caller and the second parameter is
// the reference to the callee. It must return false if the attributes of the
// caller and callee are incompatible, and true otherwise.
string CompatFunc = F;
string AttrName = "";
}

class CompatRuleAttr<string F, string Attr> : CompatRule<F> {
// The checker function is extended with an third argument as the function attribute string.
// bool(const Function&, const Function&, const StringRef&)"
string AttrName = Attr;
}

def : CompatRule<"isEqual<SanitizeAddressAttr>">;
Expand All @@ -359,7 +366,10 @@ def : CompatRule<"isEqual<ShadowCallStackAttr>">;
def : CompatRule<"isEqual<UseSampleProfileAttr>">;
def : CompatRule<"isEqual<NoProfileAttr>">;
def : CompatRule<"checkDenormMode">;

def : CompatRule<"checkStrictFP">;
def : CompatRuleAttr<"isEqual", "sign-return-address">;
def : CompatRuleAttr<"isEqual", "sign-return-address-key">;
def : CompatRuleAttr<"isEqual", "branch-protection-pauth-lr">;

class MergeRule<string F> {
// The name of the function called to merge the attributes of the caller and
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2039,12 +2039,24 @@ static bool checkDenormMode(const Function &Caller, const Function &Callee) {
return false;
}

static bool checkStrictFP(const Function &Caller, const Function &Callee) {
// Do not inline strictfp function into non-strictfp one. It would require
// conversion of all FP operations in host function to constrained intrinsics.
return !(Callee.getAttributes().hasFnAttr(Attribute::StrictFP) &&
!Caller.getAttributes().hasFnAttr(Attribute::StrictFP));
}

template<typename AttrClass>
static bool isEqual(const Function &Caller, const Function &Callee) {
return Caller.getFnAttribute(AttrClass::getKind()) ==
Callee.getFnAttribute(AttrClass::getKind());
}

static bool isEqual(const Function &Caller, const Function &Callee,
const StringRef &AttrName) {
return Caller.getFnAttribute(AttrName) == Callee.getFnAttribute(AttrName);
}

/// Compute the logical AND of the attributes of the caller and the
/// callee.
///
Expand Down
7 changes: 0 additions & 7 deletions llvm/lib/Transforms/Utils/InlineFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2103,13 +2103,6 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
BasicBlock *OrigBB = CB.getParent();
Function *Caller = OrigBB->getParent();

// Do not inline strictfp function into non-strictfp one. It would require
// conversion of all FP operations in host function to constrained intrinsics.
if (CalledFunc->getAttributes().hasFnAttr(Attribute::StrictFP) &&
!Caller->getAttributes().hasFnAttr(Attribute::StrictFP)) {
return InlineResult::failure("incompatible strictfp attributes");
}

// GC poses two hazards to inlining, which only occur when the callee has GC:
// 1. If the caller has no GC, then the callee's GC must be propagated to the
// caller.
Expand Down
104 changes: 104 additions & 0 deletions llvm/test/Transforms/Inline/inline-sign-return-address.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
; Check the inliner doesn't inline a function with different sign return address schemes.
; RUN: opt < %s -passes=inline -S | FileCheck %s

define internal void @foo_all() #0 {
ret void
}

define internal void @foo_nonleaf() #1 {
ret void
}

define internal void @foo_none() #2 {
ret void
}

define internal void @foo_lr() #3 {
ret void
}

define internal void @foo_bkey() #4 {
ret void
}

define dso_local void @bar_all() #0 {
; CHECK-LABEL: bar_all
; CHECK-NOT: call void @foo_all()
; CHECK-NEXT: call void @foo_nonleaf()
; CHECK-NEXT: call void @foo_none()
; CHECK-NEXT: call void @foo_lr()
; CHECK-NEXT: call void @foo_bkey()
call void @foo_all()
call void @foo_nonleaf()
call void @foo_none()
call void @foo_lr()
call void @foo_bkey()
ret void
}

define dso_local void @bar_nonleaf() #1 {
; CHECK-LABEL: bar_nonleaf
; CHECK-NEXT: call void @foo_all()
; CHECK-NOT: call void @foo_nonleaf()
; CHECK-NEXT: call void @foo_none()
; CHECK-NEXT: call void @foo_lr()
; CHECK-NEXT: call void @foo_bkey()
call void @foo_all()
call void @foo_nonleaf()
call void @foo_none()
call void @foo_lr()
call void @foo_bkey()
ret void
}

define dso_local void @bar_none() #2 {
; CHECK-LABEL: bar_none
; CHECK-NEXT: call void @foo_all()
; CHECK-NEXT: call void @foo_nonleaf()
; CHECK-NOT: call void @foo_none()
; CHECK-NEXT: call void @foo_lr()
; CHECK-NEXT: call void @foo_bkey()
call void @foo_all()
call void @foo_nonleaf()
call void @foo_none()
call void @foo_lr()
call void @foo_bkey()
ret void
}

define dso_local void @bar_lr() #3 {
; CHECK-LABEL: bar_lr
; CHECK-NEXT: call void @foo_all()
; CHECK-NEXT: call void @foo_nonleaf()
; CHECK-NEXT: call void @foo_none()
; CHECK-NOT: call void @foo_lr()
; CHECK-NEXT: call void @foo_bkey()
call void @foo_all()
call void @foo_nonleaf()
call void @foo_none()
call void @foo_lr()
call void @foo_bkey()
ret void
}

define dso_local void @bar_bkey() #4 {
; CHECK-LABEL: bar_bkey
; CHECK-NEXT: call void @foo_all()
; CHECK-NEXT: call void @foo_nonleaf()
; CHECK-NEXT: call void @foo_none()
; CHECK-NEXT: call void @foo_lr()
; CHECK-NOT: call void @foo_bkey()
call void @foo_all()
call void @foo_nonleaf()
call void @foo_none()
call void @foo_lr()
call void @foo_bkey()
ret void
}


attributes #0 = { "branch-protection-pauth-lr"="false" "sign-return-address"="all" }
attributes #1 = { "branch-protection-pauth-lr"="false" "sign-return-address"="non-leaf" }
attributes #2 = { "branch-protection-pauth-lr"="false" "sign-return-address"="none" }
attributes #3 = { "branch-protection-pauth-lr"="true" "sign-return-address"="non-leaf" }
attributes #4 = { "branch-protection-pauth-lr"="true" "sign-return-address"="non-leaf" "sign-return-address-key"="b_key" }
7 changes: 6 additions & 1 deletion llvm/utils/TableGen/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,12 @@ void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) {

for (auto *Rule : CompatRules) {
StringRef FuncName = Rule->getValueAsString("CompatFunc");
OS << " Ret &= " << FuncName << "(Caller, Callee);\n";
StringRef AttrName = Rule->getValueAsString("AttrName");
if (AttrName.empty())
OS << " Ret &= " << FuncName << "(Caller, Callee);\n";
else
OS << " Ret &= " << FuncName << "(Caller, Callee, \"" << AttrName
<< "\");\n";
}

OS << "\n";
Expand Down

0 comments on commit 823a939

Please sign in to comment.