-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[StackFrameLayoutAnalysis] Support more SlotTypes #100562
Conversation
Add new SlotTypes to StackFrameLayoutAnalysis to disambiguate Fixed and Variable-Sized stack slots from Variable slots. As Offsets are unreliable for VLA-area objects, sort these to the end of the list - using the Frame Index to ensure a deterministic order when Offsets are equal.
@llvm/pr-subscribers-backend-aarch64 @llvm/pr-subscribers-backend-x86 Author: Hari Limaye (hazzlim) ChangesAdd new SlotTypes to StackFrameLayoutAnalysis to disambiguate Fixed and Variable-Sized stack slots from Variable slots. As Offsets are unreliable for VLA-area objects, sort these to the end of the list - using the Frame Index to ensure a deterministic order when Offsets are equal. Full diff: https://github.com/llvm/llvm-project/pull/100562.diff 3 Files Affected:
diff --git a/llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp b/llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp
index ff77685f8f354..d69f0a2f538a7 100644
--- a/llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp
+++ b/llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp
@@ -51,6 +51,8 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
enum SlotType {
Spill, // a Spill slot
+ Fixed, // a Fixed slot (e.g. arguments passed on the stack)
+ VariableSized, // a variable sized object
StackProtector, // Stack Protector slot
Variable, // a slot used to store a local data (could be a tmp)
Invalid // It's an error for a slot to have this type
@@ -72,17 +74,29 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
Scalable = MFI.getStackID(Idx) == TargetStackID::ScalableVector;
if (MFI.isSpillSlotObjectIndex(Idx))
SlotTy = SlotType::Spill;
- else if (Idx == MFI.getStackProtectorIndex())
+ else if (MFI.isFixedObjectIndex(Idx))
+ SlotTy = SlotType::Fixed;
+ else if (MFI.isVariableSizedObjectIndex(Idx))
+ SlotTy = SlotType::VariableSized;
+ else if (MFI.hasStackProtectorIndex() &&
+ Idx == MFI.getStackProtectorIndex())
SlotTy = SlotType::StackProtector;
else
SlotTy = SlotType::Variable;
}
+ bool isVarSize() const { return SlotTy == SlotType::VariableSized; }
+
// We use this to sort in reverse order, so that the layout is displayed
- // correctly.
+ // correctly. Variable sized slots are sorted to the end of the list, and
+ // the Slot index is used to ensure deterministic order when offsets are
+ // equal.
bool operator<(const SlotData &Rhs) const {
- return (Offset.getFixed() + Offset.getScalable()) >
- (Rhs.Offset.getFixed() + Rhs.Offset.getScalable());
+ return std::make_tuple(!isVarSize(),
+ Offset.getFixed() + Offset.getScalable(), Slot) >
+ std::make_tuple(!Rhs.isVarSize(),
+ Rhs.Offset.getFixed() + Rhs.Offset.getScalable(),
+ Rhs.Slot);
}
};
@@ -121,6 +135,10 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
switch (Ty) {
case SlotType::Spill:
return "Spill";
+ case SlotType::Fixed:
+ return "Fixed";
+ case SlotType::VariableSized:
+ return "VariableSized";
case SlotType::StackProtector:
return "Protector";
case SlotType::Variable:
diff --git a/llvm/test/CodeGen/AArch64/sve-stack-frame-layout.ll b/llvm/test/CodeGen/AArch64/sve-stack-frame-layout.ll
index 36bca2ebd4ada..431c9dc76508f 100644
--- a/llvm/test/CodeGen/AArch64/sve-stack-frame-layout.ll
+++ b/llvm/test/CodeGen/AArch64/sve-stack-frame-layout.ll
@@ -147,10 +147,11 @@ entry:
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-8], Type: Spill, Align: 8, Size: 8
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-24], Type: Spill, Align: 8, Size: 8
-; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-32], Type: Variable, Align: 1, Size: 0
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-32], Type: Spill, Align: 8, Size: 8
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-32-16 x vscale], Type: Variable, Align: 16, Size: vscale x 16
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-40-16 x vscale], Type: Variable, Align: 8, Size: 8
+; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-32], Type: VariableSized, Align: 1, Size: 0
+; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-32], Type: VariableSized, Align: 1, Size: 0
define i32 @csr_d8_allocnxv4i32i32f64_vla(double %d, i32 %i) "aarch64_pstate_sm_compatible" {
; CHECK-LABEL: csr_d8_allocnxv4i32i32f64_vla:
@@ -172,7 +173,10 @@ define i32 @csr_d8_allocnxv4i32i32f64_vla(double %d, i32 %i) "aarch64_pstate_sm_
; CHECK-NEXT: mov x9, sp
; CHECK-NEXT: add x8, x8, #15
; CHECK-NEXT: and x8, x8, #0x7fffffff0
-; CHECK-NEXT: sub x8, x9, x8
+; CHECK-NEXT: sub x9, x9, x8
+; CHECK-NEXT: mov sp, x9
+; CHECK-NEXT: mov x10, sp
+; CHECK-NEXT: sub x8, x10, x8
; CHECK-NEXT: mov sp, x8
; CHECK-NEXT: mov z1.s, #0 // =0x0
; CHECK-NEXT: ptrue p0.s
@@ -181,8 +185,9 @@ define i32 @csr_d8_allocnxv4i32i32f64_vla(double %d, i32 %i) "aarch64_pstate_sm_
; CHECK-NEXT: str wzr, [x8]
; CHECK-NEXT: sub x8, x29, #8
; CHECK-NEXT: mov w0, wzr
-; CHECK-NEXT: str d0, [x19, #8]
+; CHECK-NEXT: str wzr, [x9]
; CHECK-NEXT: st1w { z1.s }, p0, [x8, #-1, mul vl]
+; CHECK-NEXT: str d0, [x19, #8]
; CHECK-NEXT: sub sp, x29, #8
; CHECK-NEXT: ldp x29, x30, [sp, #8] // 16-byte Folded Reload
; CHECK-NEXT: ldr x19, [sp, #24] // 8-byte Folded Reload
@@ -191,18 +196,20 @@ define i32 @csr_d8_allocnxv4i32i32f64_vla(double %d, i32 %i) "aarch64_pstate_sm_
entry:
%a = alloca <vscale x 4 x i32>
%0 = zext i32 %i to i64
- %b = alloca i32, i64 %0
+ %vla0 = alloca i32, i64 %0
+ %vla1 = alloca i32, i64 %0
%c = alloca double
tail call void asm sideeffect "", "~{d8}"() #1
store <vscale x 4 x i32> zeroinitializer, ptr %a
- store i32 zeroinitializer, ptr %b
+ store i32 zeroinitializer, ptr %vla0
+ store i32 zeroinitializer, ptr %vla1
store double %d, ptr %c
ret i32 0
}
; CHECK-FRAMELAYOUT-LABEL: Function: csr_d8_allocnxv4i32i32f64_stackargsi32f64
-; CHECK-FRAMELAYOUT-NEXT: Offset: [SP+8], Type: Variable, Align: 8, Size: 4
-; CHECK-FRAMELAYOUT-NEXT: Offset: [SP+0], Type: Protector, Align: 16, Size: 8
+; CHECK-FRAMELAYOUT-NEXT: Offset: [SP+8], Type: Fixed, Align: 8, Size: 4
+; CHECK-FRAMELAYOUT-NEXT: Offset: [SP+0], Type: Fixed, Align: 16, Size: 8
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-8], Type: Spill, Align: 8, Size: 8
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-16-16 x vscale], Type: Variable, Align: 16, Size: vscale x 16
@@ -289,7 +296,7 @@ entry:
}
; CHECK-FRAMELAYOUT-LABEL: Function: svecc_z8_allocnxv4i32i32f64_stackargsi32_fp
-; CHECK-FRAMELAYOUT-NEXT: Offset: [SP+0], Type: Protector, Align: 16, Size: 4
+; CHECK-FRAMELAYOUT-NEXT: Offset: [SP+0], Type: Fixed, Align: 16, Size: 4
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-8], Type: Spill, Align: 8, Size: 8
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-16-16 x vscale], Type: Spill, Align: 16, Size: vscale x 16
@@ -514,7 +521,7 @@ declare ptr @memset(ptr, i32, i32)
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-104], Type: Spill, Align: 8, Size: 8
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-112], Type: Spill, Align: 8, Size: 8
; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-128], Type: Variable, Align: 16, Size: 16
-; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-128], Type: Variable, Align: 16, Size: 0
+; CHECK-FRAMELAYOUT-NEXT: Offset: [SP-128], Type: VariableSized, Align: 16, Size: 0
define i32 @vastate(i32 %x) "aarch64_inout_za" "aarch64_pstate_sm_enabled" "target-features"="+sme" {
; CHECK-LABEL: vastate:
diff --git a/llvm/test/CodeGen/X86/stack-frame-layout-remarks.ll b/llvm/test/CodeGen/X86/stack-frame-layout-remarks.ll
index cd5edcf2ae502..d8ce5b041042e 100644
--- a/llvm/test/CodeGen/X86/stack-frame-layout-remarks.ll
+++ b/llvm/test/CodeGen/X86/stack-frame-layout-remarks.ll
@@ -35,7 +35,7 @@ entry:
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
; BOTH: Function: cleanup_array
-; BOTH-NEXT: Offset: [SP+4], Type: Protector, Align: 16, Size: 4
+; BOTH-NEXT: Offset: [SP+4], Type: Fixed, Align: 16, Size: 4
; DEBUG: a @ dot.c:13
; STRIPPED-NOT: a @ dot.c:13
; BOTH: Offset: [SP-4], Type: Spill, Align: 8, Size: 4
@@ -47,7 +47,7 @@ define void @cleanup_array(ptr %0) #1 {
}
; BOTH: Function: cleanup_result
-; BOTH: Offset: [SP+4], Type: Protector, Align: 16, Size: 4
+; BOTH: Offset: [SP+4], Type: Fixed, Align: 16, Size: 4
; DEBUG: res @ dot.c:21
; STRIPPED-NOT: res @ dot.c:21
; BOTH: Offset: [SP-4], Type: Spill, Align: 8, Size: 4
@@ -59,11 +59,11 @@ define void @cleanup_result(ptr %0) #1 {
}
; BOTH: Function: do_work
-; BOTH: Offset: [SP+12], Type: Variable, Align: 8, Size: 4
+; BOTH: Offset: [SP+12], Type: Fixed, Align: 8, Size: 4
; DEBUG: out @ dot.c:32
; STRIPPED-NOT: out @ dot.c:32
-; BOTH: Offset: [SP+8], Type: Variable, Align: 4, Size: 4
-; BOTH: Offset: [SP+4], Type: Protector, Align: 16, Size: 4
+; BOTH: Offset: [SP+8], Type: Fixed, Align: 4, Size: 4
+; BOTH: Offset: [SP+4], Type: Fixed, Align: 16, Size: 4
; DEBUG: A @ dot.c:32
; STRIPPED-NOT: A @ dot.c:32
; BOTH: Offset: [SP-4], Type: Spill, Align: 8, Size: 4
@@ -125,7 +125,7 @@ define i32 @do_work(ptr %0, ptr %1, ptr %2) #2 {
}
; BOTH: Function: gen_array
-; BOTH: Offset: [SP+4], Type: Protector, Align: 16, Size: 4
+; BOTH: Offset: [SP+4], Type: Fixed, Align: 16, Size: 4
; DEBUG: size @ dot.c:62
; STRIPPED-NOT: size @ dot.c:62
; BOTH: Offset: [SP-4], Type: Spill, Align: 8, Size: 4
|
This should fix buildbot failure https://lab.llvm.org/buildbot/#/builders/16/builds/2383 caused by #100386 (due to non-deterministic sorting when offsets are equal). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is mostly OK, but I wonder if we also just always need to sort by all the printed fields? So, offset, type, alignment and size? I think that may be necessary to avoid non determinism. If we’re doing that, then we probably don’t need to put VariableSize at then end.
Can you add those other fields to the comparison?
Ah I missed the slot number comparisons. Feel free to ignore my previous comment |
Great - thanks so much for reviewing, and sorry if that wasn't initially very clear! My thinking behind explicitly sorting slots with Type VariableSize to the end is that we currently don't generate correct offsets for these, but they do actually end up at "the end" (the most negative offset from the incoming SP). So this sorting order gives us a more correct layout than we otherwise would, even though the offset values are wrong. I can update the comment to make this more explicit, if you think that would be useful? |
Better comments never hurt, but I’m fine either way. The offsets are something I’m planning to look into when I get some time. |
I've updated the comment to be a bit more explanatory w.r.t. sorting VariableSized slots to the end. |
Great. Thanks. FYI: the bot failure seems to be related to Python, so you're probably safe to land this. |
Summary: Add new SlotTypes to StackFrameLayoutAnalysis to disambiguate Fixed and Variable-Sized stack slots from Variable slots. As Offsets are unreliable for VLA-area objects, sort these to the end of the list - using the Frame Index to ensure a deterministic order when Offsets are equal. Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60250536
Add new SlotTypes to StackFrameLayoutAnalysis to disambiguate Fixed and Variable-Sized stack slots from Variable slots. As Offsets are unreliable for VLA-area objects, sort these to the end of the list - using the Frame Index to ensure a deterministic order when Offsets are equal. (cherry picked from commit e31794f)
/pull-request #101042 |
Add new SlotTypes to StackFrameLayoutAnalysis to disambiguate Fixed and Variable-Sized stack slots from Variable slots. As Offsets are unreliable for VLA-area objects, sort these to the end of the list - using the Frame Index to ensure a deterministic order when Offsets are equal.