Skip to content

Commit 3ab7c6a

Browse files
DanielKristofKissllvmbot
authored andcommitted
[llvm][AArch64] Autoupgrade function attributes from Module attributes. (llvm#82763)
sign-return-address and similar module attributes should be propagated to the function level before got merged because module flags may contradict and this information is not recoverable. Generated code will match with the normal linking flow. Refactored version of (llvm#80640). Run the attribute copy only during IRMove. (cherry picked from commit ded5de1)
1 parent 461274b commit 3ab7c6a

File tree

6 files changed

+122
-3
lines changed

6 files changed

+122
-3
lines changed

llvm/include/llvm/IR/AutoUpgrade.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ namespace llvm {
8888
/// info. Return true if module is modified.
8989
bool UpgradeDebugInfo(Module &M);
9090

91+
/// Copies module attributes to the functions in the module.
92+
void CopyModuleAttrToFunctions(Module &M);
93+
9194
/// Check whether a string looks like an old loop attachment tag.
9295
inline bool mayBeOldLoopAttachmentTag(StringRef Name) {
9396
return Name.starts_with("llvm.vectorizer.");

llvm/lib/IR/AutoUpgrade.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5169,6 +5169,72 @@ void llvm::UpgradeFunctionAttributes(Function &F) {
51695169
Arg.removeAttrs(AttributeFuncs::typeIncompatible(Arg.getType()));
51705170
}
51715171

5172+
// Check if the module attribute is present and not zero.
5173+
static bool isModuleAttributeSet(Module &M, const StringRef &ModAttr) {
5174+
const auto *Attr =
5175+
mdconst::extract_or_null<ConstantInt>(M.getModuleFlag(ModAttr));
5176+
return Attr && Attr->getZExtValue();
5177+
}
5178+
5179+
// Copy an attribute from module to the function if exists.
5180+
// First value of the pair is used when the module attribute is not zero
5181+
// the second otherwise.
5182+
static void
5183+
CopyModuleAttributeToFunction(Function &F, StringRef FnAttrName,
5184+
StringRef ModAttrName,
5185+
std::pair<StringRef, StringRef> Values) {
5186+
if (F.hasFnAttribute(FnAttrName))
5187+
return;
5188+
F.addFnAttr(FnAttrName, isModuleAttributeSet(*F.getParent(), ModAttrName)
5189+
? Values.first
5190+
: Values.second);
5191+
}
5192+
5193+
// Copy a boolean attribute from module to the function if exists.
5194+
// Module attribute treated false if zero otherwise true.
5195+
static void CopyModuleAttributeToFunction(Function &F, StringRef AttrName) {
5196+
CopyModuleAttributeToFunction(
5197+
F, AttrName, AttrName,
5198+
std::make_pair<StringRef, StringRef>("true", "false"));
5199+
}
5200+
5201+
// Copy an attribute from module to the function if exists.
5202+
// First value of the pair is used when the module attribute is not zero
5203+
// the second otherwise.
5204+
static void
5205+
CopyModuleAttributeToFunction(Function &F, StringRef AttrName,
5206+
std::pair<StringRef, StringRef> Values) {
5207+
CopyModuleAttributeToFunction(F, AttrName, AttrName, Values);
5208+
}
5209+
5210+
void llvm::CopyModuleAttrToFunctions(Module &M) {
5211+
Triple T(M.getTargetTriple());
5212+
if (!T.isThumb() && !T.isARM() && !T.isAArch64())
5213+
return;
5214+
5215+
for (Function &F : M.getFunctionList()) {
5216+
if (F.isDeclaration())
5217+
continue;
5218+
5219+
if (!F.hasFnAttribute("sign-return-address")) {
5220+
StringRef SignType = "none";
5221+
if (isModuleAttributeSet(M, "sign-return-address"))
5222+
SignType = "non-leaf";
5223+
5224+
if (isModuleAttributeSet(M, "sign-return-address-all"))
5225+
SignType = "all";
5226+
5227+
F.addFnAttr("sign-return-address", SignType);
5228+
}
5229+
CopyModuleAttributeToFunction(F, "branch-target-enforcement");
5230+
CopyModuleAttributeToFunction(F, "branch-protection-pauth-lr");
5231+
CopyModuleAttributeToFunction(F, "guarded-control-stack");
5232+
CopyModuleAttributeToFunction(
5233+
F, "sign-return-address-key",
5234+
std::make_pair<StringRef, StringRef>("b_key", "a_key"));
5235+
}
5236+
}
5237+
51725238
static bool isOldLoopArgument(Metadata *MD) {
51735239
auto *T = dyn_cast_or_null<MDTuple>(MD);
51745240
if (!T)

llvm/lib/Linker/IRMover.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,6 +1605,11 @@ Error IRLinker::run() {
16051605
// Loop over all of the linked values to compute type mappings.
16061606
computeTypeMapping();
16071607

1608+
// Convert module level attributes to function level attributes because
1609+
// after merging modules the attributes might change and would have different
1610+
// effect on the functions as the original module would have.
1611+
CopyModuleAttrToFunctions(*SrcM);
1612+
16081613
std::reverse(Worklist.begin(), Worklist.end());
16091614
while (!Worklist.empty()) {
16101615
GlobalValue *GV = Worklist.back();

llvm/test/LTO/AArch64/link-branch-target-enforcement.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ entry:
3232
; CHECK-DUMP: <main>:
3333
; CHECK-DUMP: bl 0x8 <main+0x8>
3434
; CHECK-DUMP: <foo>:
35+
; CHECK-DUMP: paciasp
3536

3637
; `main` doesn't support BTI while `foo` does, so in the binary
3738
; we should see only PAC which is supported by both.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
; Testcase to check that module with different branch-target-enforcement can
2+
; be mixed.
3+
;
4+
; RUN: llvm-as %s -o %t1.bc
5+
; RUN: llvm-as %p/Inputs/foo.ll -o %t2.bc
6+
; RUN: llvm-lto -exported-symbol main \
7+
; RUN: -exported-symbol foo \
8+
; RUN: -filetype=obj \
9+
; RUN: %t2.bc %t1.bc \
10+
; RUN: -o %t1.exe 2>&1
11+
; RUN: llvm-objdump -d %t1.exe | FileCheck --check-prefix=CHECK-DUMP %s
12+
; RUN: llvm-readelf -n %t1.exe | FileCheck --allow-empty --check-prefix=CHECK-PROP %s
13+
14+
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
15+
target triple = "aarch64-unknown-linux-gnu"
16+
17+
declare i32 @foo();
18+
19+
define i32 @main() {
20+
entry:
21+
%add = call i32 @foo()
22+
ret i32 %add
23+
}
24+
25+
!llvm.module.flags = !{!0, !1, !2, !3 }
26+
!0 = !{i32 8, !"branch-target-enforcement", i32 0}
27+
!1 = !{i32 8, !"sign-return-address", i32 0}
28+
!2 = !{i32 8, !"sign-return-address-all", i32 0}
29+
!3 = !{i32 8, !"sign-return-address-with-bkey", i32 0}
30+
31+
; CHECK-DUMP: <foo>:
32+
; CHECK-DUMP: paciasp
33+
; CHECK-DUMP: mov w0, #0x2a
34+
; CHECK-DUMP: autiasp
35+
; CHECK-DUMP: ret
36+
; CHECK-DUMP: <main>:
37+
; CHECK-DUMP-NOT: paciasp
38+
; CHECK-DUMP: str x30,
39+
; CHECK-DUMP: bl 0x14 <main+0x4>
40+
41+
; `main` doesn't support PAC sign-return-address while `foo` does, so in the binary
42+
; we should not see anything.
43+
; CHECK-PROP-NOT: Properties: aarch64 feature: PAC

llvm/test/Linker/link-arm-and-thumb.ll

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ entry:
1313
ret i32 %add
1414
}
1515

16-
; CHECK: define i32 @main() {
16+
; CHECK: define i32 @main() [[MAIN_ATTRS:#[0-9]+]]
1717
; CHECK: define i32 @foo(i32 %a, i32 %b) [[ARM_ATTRS:#[0-9]+]]
1818
; CHECK: define i32 @bar(i32 %a, i32 %b) [[THUMB_ATTRS:#[0-9]+]]
1919

20-
; CHECK: attributes [[ARM_ATTRS]] = { "target-features"="-thumb-mode" }
21-
; CHECK: attributes [[THUMB_ATTRS]] = { "target-features"="+thumb-mode" }
20+
; CHECK: attributes [[MAIN_ATTRS]] = { {{.*}} }
21+
; CHECK: attributes [[ARM_ATTRS]] = { {{.*}} "target-features"="-thumb-mode" }
22+
; CHECK: attributes [[THUMB_ATTRS]] = { {{.*}} "target-features"="+thumb-mode" }
2223

2324
; STDERR-NOT: warning: Linking two modules of different target triples:

0 commit comments

Comments
 (0)