Skip to content

Commit

Permalink
[llvm][AArch64] Do not inline a function with different signing schem…
Browse files Browse the repository at this point in the history
…e. (#80642)

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 authored Feb 23, 2024
1 parent 531e8c2 commit 6fae3e7
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 8 deletions.
28 changes: 21 additions & 7 deletions llvm/include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -339,14 +339,26 @@ def UseSampleProfile : StrBoolAttr<"use-sample-profile">;
def DenormalFPMath : ComplexStrAttr<"denormal-fp-math", [FnAttr]>;
def DenormalFPMathF32 : ComplexStrAttr<"denormal-fp-math-f32", [FnAttr]>;

// Attribute compatiblity rules are generated to check the attribute of the
// caller and callee and decide whether inlining should be allowed. CompatRule
// and child classes are used for the rule generation. CompatRule takes only a
// compare function which could be templated with the attribute type.
// CompatRuleStrAttr takes the compare function and the string attribute for
// checking compatibility for inline substitution.
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
// 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.
// The function's 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 CompatRuleStrAttr<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 +371,9 @@ def : CompatRule<"isEqual<ShadowCallStackAttr>">;
def : CompatRule<"isEqual<UseSampleProfileAttr>">;
def : CompatRule<"isEqual<NoProfileAttr>">;
def : CompatRule<"checkDenormMode">;

def : CompatRuleStrAttr<"isEqual", "sign-return-address">;
def : CompatRuleStrAttr<"isEqual", "sign-return-address-key">;
def : CompatRuleStrAttr<"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
5 changes: 5 additions & 0 deletions llvm/lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2045,6 +2045,11 @@ static bool isEqual(const Function &Caller, const Function &Callee) {
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
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" }
6 changes: 5 additions & 1 deletion llvm/utils/TableGen/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) {

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

OS << "\n";
Expand Down

0 comments on commit 6fae3e7

Please sign in to comment.