-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[Win][llvm]MSVC inliner section behavior compat #146965
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-llvm-ir Author: Adam Glass (AdamGlass) ChangesMSVC implements has a compatibility test/rule for inlining between sections. Inlining instances that do not meet these rules are rejected. The rules are:
We are at present unaware of any public documentation of these behaviors. This PR implements the above rules/behavior and constrains their application to the MSVC environment. Q: Does this PAGE prefix have an implication for the section flags? Full diff: https://github.com/llvm/llvm-project/pull/146965.diff 3 Files Affected:
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 112853965407c..3daf5819d421e 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -455,6 +455,7 @@ def : CompatRule<"isEqual<UseSampleProfileAttr>">;
def : CompatRule<"isEqual<NoProfileAttr>">;
def : CompatRule<"checkDenormMode">;
def : CompatRule<"checkStrictFP">;
+def : CompatRule<"checkSectionsMSVC">;
def : CompatRuleStrAttr<"isEqual", "sign-return-address">;
def : CompatRuleStrAttr<"isEqual", "sign-return-address-key">;
def : CompatRuleStrAttr<"isEqual", "branch-protection-pauth-lr">;
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index d1fbcb9e893a7..8f5e4d2bd301e 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -2508,6 +2508,48 @@ static bool checkStrictFP(const Function &Caller, const Function &Callee) {
Caller.getAttributes().hasFnAttr(Attribute::StrictFP);
}
+static bool checkSectionsMSVC(const Function &Caller, const Function &Callee) {
+ // Apply inlining section compatibility test only to MSVC environment
+ if (!Caller.getParent()->getTargetTriple().isWindowsMSVCEnvironment())
+ return true;
+
+ StringRef CallerSection = Caller.getSection();
+ StringRef CalleeSection = Callee.getSection();
+
+ // Sections match, inlining ok
+ if (!CallerSection.compare(CalleeSection))
+ return true;
+
+ bool isCallerPaged = CallerSection.starts_with("PAGE");
+ bool isCalleePaged = CalleeSection.starts_with("PAGE");
+
+ // Paged caller & callee
+ if (isCallerPaged && isCalleePaged) {
+ // Compare section names up to '$' separator if present
+ size_t CallerComparable = CallerSection.size();
+ size_t CalleeComparable = CalleeSection.size();
+ size_t CallerSep = CallerSection.find('$');
+ size_t CalleeSep = CalleeSection.find('$');
+
+ if (CallerSep != StringRef::npos)
+ CallerComparable = CallerSep;
+ if (CalleeSep != StringRef::npos)
+ CalleeComparable = CalleeSep;
+ if (CallerComparable != CalleeComparable)
+ return false;
+
+ StringRef CallerComparableSection =
+ CallerSection.substr(0, CallerComparable);
+ StringRef CalleeComparableSection =
+ CalleeSection.substr(0, CallerComparable);
+ return !CallerComparableSection.compare(CalleeComparableSection);
+ } else if (isCalleePaged || isCallerPaged)
+ // Paged and unpaged code must not be mixed
+ return false;
+
+ return true;
+}
+
template<typename AttrClass>
static bool isEqual(const Function &Caller, const Function &Callee) {
return Caller.getFnAttribute(AttrClass::getKind()) ==
diff --git a/llvm/test/Transforms/Inline/inline-msvc-sections.ll b/llvm/test/Transforms/Inline/inline-msvc-sections.ll
new file mode 100644
index 0000000000000..5c4b199f88ee0
--- /dev/null
+++ b/llvm/test/Transforms/Inline/inline-msvc-sections.ll
@@ -0,0 +1,157 @@
+; RUN: opt < %s -passes=inline -inline-threshold=100 -S | FileCheck %s
+; RUN: opt < %s -passes='cgscc(inline)' -inline-threshold=100 -S | FileCheck %s
+; RUN: opt < %s -mtriple=aarch64-windows-msvc -passes=inline -inline-threshold=100 -S | FileCheck %s -check-prefix=MSVC
+; RUN: opt < %s -mtriple=aarch64-windows-msvc -passes='cgscc(inline)' -inline-threshold=100 -S | FileCheck %s -check-prefix=MSVC
+
+define i32 @nosection_callee(i32 %x) {
+ %x1 = add i32 %x, 1
+ %x2 = add i32 %x1, 1
+ %x3 = add i32 %x2, 1
+ call void @extern()
+ ret i32 %x3
+}
+
+define i32 @section_callee(i32 %x) section "FOO" {
+ %x1 = add i32 %x, 1
+ %x2 = add i32 %x1, 1
+ %x3 = add i32 %x2, 1
+ call void @extern()
+ ret i32 %x3
+}
+
+define i32 @sectionpostfix_callee(i32 %x) section "FOO$BBBB" {
+ %x1 = add i32 %x, 1
+ %x2 = add i32 %x1, 1
+ %x3 = add i32 %x2, 1
+ call void @extern()
+ ret i32 %x3
+}
+
+define i32 @paged_callee(i32 %x) section "PAGE" {
+ %x1 = add i32 %x, 1
+ %x2 = add i32 %x1, 1
+ %x3 = add i32 %x2, 1
+ call void @extern()
+ ret i32 %x3
+}
+
+define i32 @pagedpostfix_callee(i32 %x) section "PAGE$aaa" {
+ %x1 = add i32 %x, 1
+ %x2 = add i32 %x1, 1
+ %x3 = add i32 %x2, 1
+ call void @extern()
+ ret i32 %x3
+}
+
+define i32 @nosection_caller(i32 %y1) {
+ %y2 = call i32 @nosection_callee(i32 %y1)
+ %y3 = call i32 @section_callee(i32 %y2)
+ %y4 = call i32 @sectionpostfix_callee(i32 %y3)
+ %y5 = call i32 @paged_callee(i32 %y4)
+ %y6 = call i32 @pagedpostfix_callee(i32 %y5)
+ ret i32 %y6
+}
+
+; CHECK-LABEL: @nosection_caller
+; CHECK-NOT: @nosection_callee
+; CHECK-NOT: @section_callee
+; CHECK-NOT: @sectionpostfix_callee
+; CHECK-NOT: @paged_callee
+; CHECK-NOT: @pagedpostfix_callee
+; MSVC-LABEL: @nosection_caller
+; MSVC-NOT: @nosection_callee
+; MSVC-NOT: @section_callee
+; MSVC-NOT: @sectionpostfix_callee
+; MSVC: @paged_callee
+; MSVC: @pagedpostfix_callee
+
+define i32 @section_caller(i32 %y1) section "FOO" {
+ %y2 = call i32 @nosection_callee(i32 %y1)
+ %y3 = call i32 @section_callee(i32 %y2)
+ %y4 = call i32 @sectionpostfix_callee(i32 %y3)
+ %y5 = call i32 @paged_callee(i32 %y4)
+ %y6 = call i32 @pagedpostfix_callee(i32 %y5)
+ ret i32 %y6
+}
+
+; CHECK-LABEL: @section_caller
+; CHECK-NOT: @nosection_callee
+; CHECK-NOT: @section_callee
+; CHECK-NOT: @sectionpostfix_callee
+; CHECK-NOT: @paged_callee
+; CHECK-NOT: @pagedpostfix_callee
+; MSVC-LABEL: @section_caller
+; MSVC-NOT: @nosection_callee
+; MSVC-NOT: @section_callee
+; MSVC-NOT: @sectionpostfix_callee
+; MSVC: @paged_callee
+; MSVC: @pagedpostfix_callee
+
+define i32 @sectionpostfix_caller(i32 %y1) section "FOO$ZZZ" {
+ %y2 = call i32 @nosection_callee(i32 %y1)
+ %y3 = call i32 @section_callee(i32 %y2)
+ %y4 = call i32 @sectionpostfix_callee(i32 %y3)
+ %y5 = call i32 @paged_callee(i32 %y4)
+ %y6 = call i32 @pagedpostfix_callee(i32 %y5)
+ ret i32 %y6
+}
+
+; CHECK-LABEL: @sectionpostfix_caller
+; CHECK-NOT: @nosection_callee
+; CHECK-NOT: @section_callee
+; CHECK-NOT: @sectionpostfix_callee
+; CHECK-NOT: @paged_callee
+; CHECK-NOT: @pagedpostfix_callee
+; MSVC-LABEL: @sectionpostfix_caller
+; MSVC-NOT: @nosection_callee
+; MSVC-NOT: @section_callee
+; MSVC-NOT: @sectionpostfix_callee
+; MSVC: @paged_callee
+; MSVC: @pagedpostfix_callee
+
+define i32 @paged_caller(i32 %y1) section "PAGE" {
+ %y2 = call i32 @nosection_callee(i32 %y1)
+ %y3 = call i32 @section_callee(i32 %y2)
+ %y4 = call i32 @sectionpostfix_callee(i32 %y3)
+ %y5 = call i32 @paged_callee(i32 %y4)
+ %y6 = call i32 @pagedpostfix_callee(i32 %y5)
+ ret i32 %y6
+}
+
+; CHECK-LABEL: @paged_caller
+; CHECK-NOT: @nosection_callee
+; CHECK-NOT: @section_callee
+; CHECK-NOT: @sectionpostfix_callee
+; CHECK-NOT: @paged_callee
+; CHECK-NOT: @pagedpostfix_callee
+; MSVC-LABEL: @paged_caller
+; MSVC: @nosection_callee
+; MSVC: @section_callee
+; MSVC: @sectionpostfix_callee
+; MSVC-NOT: @paged_callee
+; MSVC-NOT: @pagedpostfix_callee
+
+define i32 @pagedpostfix_caller(i32 %y1) section "PAGE$ZZZ" {
+ %y2 = call i32 @nosection_callee(i32 %y1)
+ %y3 = call i32 @section_callee(i32 %y2)
+ %y4 = call i32 @sectionpostfix_callee(i32 %y3)
+ %y5 = call i32 @paged_callee(i32 %y4)
+ %y6 = call i32 @pagedpostfix_callee(i32 %y5)
+ ret i32 %y6
+}
+
+; CHECK-LABEL: @pagedpostfix_caller
+; CHECK-NOT: @nosection_callee
+; CHECK-NOT: @section_callee
+; CHECK-NOT: @sectionpostfix_callee
+; CHECK-NOT: @paged_callee
+; CHECK-NOT: @pagedpostfix_callee
+; MSVC-LABEL: @pagedpostfix_caller
+; MSVC: @nosection_callee
+; MSVC: @section_callee
+; MSVC: @sectionpostfix_callee
+; MSVC-NOT: @paged_callee
+; MSVC-NOT: @pagedpostfix_callee
+
+declare void @extern()
+
|
MSVC implements has a compatibility test/rule for inlining between sections. Inlining instances that do not meet these rules are rejected. The rules are:
We are at present unaware of any public documentation of these behaviors.
There may be future compatibility rules associated with user-specified 'inline' and 'forceinline'.
This PR implements the above rules/behavior and constrains their application to the MSVC environment.
Test included
Q: Does this PAGE prefix have an implication for the section flags?
A: No