Skip to content

Commit 7a9286d

Browse files
[llvm][AArch64] Autoupgrade function attributes from Module attributes.
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.
1 parent 9b80ab4 commit 7a9286d

File tree

8 files changed

+133
-8
lines changed

8 files changed

+133
-8
lines changed

llvm/include/llvm/IR/AutoUpgrade.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ namespace llvm {
6767
void UpgradeSectionAttributes(Module &M);
6868

6969
/// Correct any IR that is relying on old function attribute behavior.
70-
void UpgradeFunctionAttributes(Function &F);
70+
void UpgradeFunctionAttributes(Function &F,
71+
bool ModuleMetadataIsMaterialized = false);
7172

7273
/// If the given TBAA tag uses the scalar TBAA format, create a new node
7374
/// corresponding to the upgrade to the struct-path aware TBAA format.

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6705,7 +6705,7 @@ Error BitcodeReader::materialize(GlobalValue *GV) {
67056705
}
67066706

67076707
// Look for functions that rely on old function attribute behavior.
6708-
UpgradeFunctionAttributes(*F);
6708+
UpgradeFunctionAttributes(*F, true);
67096709

67106710
// Bring in any functions that this function forward-referenced via
67116711
// blockaddresses.

llvm/lib/IR/AutoUpgrade.cpp

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5155,7 +5155,51 @@ struct StrictFPUpgradeVisitor : public InstVisitor<StrictFPUpgradeVisitor> {
51555155
};
51565156
} // namespace
51575157

5158-
void llvm::UpgradeFunctionAttributes(Function &F) {
5158+
// Check if the module attribute is present and not zero.
5159+
static bool isModuleAttributeSet(const Module *M, const StringRef &ModAttr) {
5160+
if (const auto *Attr =
5161+
mdconst::extract_or_null<ConstantInt>(M->getModuleFlag(ModAttr)))
5162+
if (Attr->getZExtValue())
5163+
return true;
5164+
return false;
5165+
}
5166+
5167+
// Copy an attribute from module to the function if exists.
5168+
// First value of the pair is used when the module attribute is not zero
5169+
// the second otherwise.
5170+
static void
5171+
CopyModuleAttributeToFunction(Function &F, StringRef FnAttrName,
5172+
StringRef ModAttrName,
5173+
std::pair<StringRef, StringRef> Values) {
5174+
Module *M = F.getParent();
5175+
assert(M && "Missing module");
5176+
if (F.hasFnAttribute(FnAttrName))
5177+
return;
5178+
if (isModuleAttributeSet(M, ModAttrName))
5179+
F.addFnAttr(FnAttrName, Values.first);
5180+
else
5181+
F.addFnAttr(FnAttrName, Values.second);
5182+
}
5183+
5184+
// Copy a boolean attribute from module to the function if exists.
5185+
// Module attribute treated false if zero otherwise true.
5186+
static void CopyModuleAttributeToFunction(Function &F, StringRef AttrName) {
5187+
CopyModuleAttributeToFunction(
5188+
F, AttrName, AttrName,
5189+
std::make_pair<StringRef, StringRef>("true", "false"));
5190+
}
5191+
5192+
// Copy an attribute from module to the function if exists.
5193+
// First value of the pair is used when the module attribute is not zero
5194+
// the second otherwise.
5195+
static void
5196+
CopyModuleAttributeToFunction(Function &F, StringRef AttrName,
5197+
std::pair<StringRef, StringRef> Values) {
5198+
CopyModuleAttributeToFunction(F, AttrName, AttrName, Values);
5199+
}
5200+
5201+
void llvm::UpgradeFunctionAttributes(Function &F,
5202+
bool ModuleMetadataIsMaterialized) {
51595203
// If a function definition doesn't have the strictfp attribute,
51605204
// convert any callsite strictfp attributes to nobuiltin.
51615205
if (!F.isDeclaration() && !F.hasFnAttribute(Attribute::StrictFP)) {
@@ -5167,6 +5211,37 @@ void llvm::UpgradeFunctionAttributes(Function &F) {
51675211
F.removeRetAttrs(AttributeFuncs::typeIncompatible(F.getReturnType()));
51685212
for (auto &Arg : F.args())
51695213
Arg.removeAttrs(AttributeFuncs::typeIncompatible(Arg.getType()));
5214+
5215+
if (!ModuleMetadataIsMaterialized)
5216+
return;
5217+
if (F.isDeclaration())
5218+
return;
5219+
Module *M = F.getParent();
5220+
if (!M)
5221+
return;
5222+
5223+
Triple T(M->getTargetTriple());
5224+
// Convert module level attributes to function level attributes because
5225+
// after merging modules the attributes might change and would have different
5226+
// effect on the functions as the original module would have.
5227+
if (T.isThumb() || T.isARM() || T.isAArch64()) {
5228+
if (!F.hasFnAttribute("sign-return-address")) {
5229+
StringRef SignType = "none";
5230+
if (isModuleAttributeSet(M, "sign-return-address"))
5231+
SignType = "non-leaf";
5232+
5233+
if (isModuleAttributeSet(M, "sign-return-address-all"))
5234+
SignType = "all";
5235+
5236+
F.addFnAttr("sign-return-address", SignType);
5237+
}
5238+
CopyModuleAttributeToFunction(F, "branch-target-enforcement");
5239+
CopyModuleAttributeToFunction(F, "branch-protection-pauth-lr");
5240+
CopyModuleAttributeToFunction(F, "guarded-control-stack");
5241+
CopyModuleAttributeToFunction(
5242+
F, "sign-return-address-key",
5243+
std::make_pair<StringRef, StringRef>("b_key", "a_key"));
5244+
}
51705245
}
51715246

51725247
static bool isOldLoopArgument(Metadata *MD) {

llvm/lib/Linker/IRMover.cpp

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

1609+
// Update function attributes before copying them to destation module.
1610+
for (Function &F : SrcM->getFunctionList())
1611+
UpgradeFunctionAttributes(F, true);
1612+
16091613
std::reverse(Worklist.begin(), Worklist.end());
16101614
while (!Worklist.empty()) {
16111615
GlobalValue *GV = Worklist.back();

llvm/test/Bitcode/upgrade-arc-runtime-calls.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ unwindBlock:
5555
// Check that auto-upgrader converts function calls to intrinsic calls. Note that
5656
// the auto-upgrader doesn't touch invoke instructions.
5757

58-
// ARC: define void @testRuntimeCalls(ptr %[[A:.*]], ptr %[[B:.*]], ptr %[[C:.*]], ptr %[[D:.*]], ptr %[[E:.*]]) personality
58+
// ARC: define void @testRuntimeCalls(ptr %[[A:.*]], ptr %[[B:.*]], ptr %[[C:.*]], ptr %[[D:.*]], ptr %[[E:.*]]) #0 personality
5959
// ARC: %[[V0:.*]] = tail call ptr @llvm.objc.autorelease(ptr %[[A]])
6060
// ARC-NEXT: tail call void @llvm.objc.autoreleasePoolPop(ptr %[[A]])
6161
// ARC-NEXT: %[[V1:.*]] = tail call ptr @llvm.objc.autoreleasePoolPush()
@@ -88,7 +88,7 @@ unwindBlock:
8888
// ARC-NEXT: tail call void @llvm.objc.arc.annotation.bottomup.bbend(ptr %[[B]], ptr %[[C]])
8989
// ARC-NEXT: invoke void @objc_autoreleasePoolPop(ptr %[[A]])
9090

91-
// NOUPGRADE: define void @testRuntimeCalls(ptr %[[A:.*]], ptr %[[B:.*]], ptr %[[C:.*]], ptr %[[D:.*]], ptr %[[E:.*]]) personality
91+
// NOUPGRADE: define void @testRuntimeCalls(ptr %[[A:.*]], ptr %[[B:.*]], ptr %[[C:.*]], ptr %[[D:.*]], ptr %[[E:.*]]) #0 personality
9292
// NOUPGRADE: %[[V0:.*]] = tail call ptr @objc_autorelease(ptr %[[A]])
9393
// NOUPGRADE-NEXT: tail call void @objc_autoreleasePoolPop(ptr %[[A]])
9494
// NOUPGRADE-NEXT: %[[V1:.*]] = tail call ptr @objc_autoreleasePoolPush()

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)