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">; def : CompatRule<"isEqual">; 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 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() +