This is an archive of the discontinued LLVM Phabricator instance.

Fixed spill stack objects are mutable
ClosedPublic

Authored by kparzysz on Aug 30 2016, 9:41 AM.

Details

Summary

CreateFixedSpillStackObject marked the created objects as immutable. This is an error, since spill stack objects are stored to, while immutable objects are assumed to never change during the function execution.

Diff Detail

Repository
rL LLVM

Event Timeline

kparzysz updated this revision to Diff 69715.Aug 30 2016, 9:41 AM
kparzysz retitled this revision from to Fixed spill stack objects are mutable.
kparzysz updated this object.
kparzysz added a reviewer: hfinkel.
kparzysz set the repository for this revision to rL LLVM.
kparzysz added a subscriber: llvm-commits.
kparzysz added a subscriber: llvm-commits.
reames requested changes to this revision.Aug 30 2016, 1:13 PM
reames added a reviewer: reames.
reames added a subscriber: reames.

At least per documentation, spill slots should be created via CreateSpillStackObject. I think you may be fixing the wrong bug. Even if not silently disabling all optimization for existing callers is not acceptable.

This revision now requires changes to proceed.Aug 30 2016, 1:13 PM
hfinkel edited edge metadata.Aug 30 2016, 1:38 PM

At least per documentation, spill slots should be created via CreateSpillStackObject. I think you may be fixing the wrong bug. Even if not silently disabling all optimization for existing callers is not acceptable.

I'm not quite sure that's right: Some ABIs have fixed-offset spill slots (e.g. PowerPC). Calling a spill slot immutable seems odd anyway, given that, by definition, you store into it. Also, they have isAliased == false regardless.

What documentation are you referring to?

Second of all, the rest of your comment sounds strange given my description of the problem. It is exactly that optimizations taking advantage of the "immutable" flag should not be taking place, given that these slots are not immutable.

What documentation are you referring to?

In the same header:
/// Create a new statically sized stack object that represents a spill slot,

/// returning a nonnegative identifier to represent it.
int CreateSpillStackObject(uint64_t Size, unsigned Alignment);

I also confirmed that the register allocator (via VirtRegMap::createSpillSlot) does use this interface.

Second of all, the rest of your comment sounds strange given my description of the problem. It is exactly that optimizations taking advantage of the "immutable" flag should not be taking place, given that these slots are not immutable.

My point is that while *spill slots* are clearly not immutable, there are other stack slots created by the same interface you modified which are. Disabling optimization of those slots is clearly not okay.

At least per documentation, spill slots should be created via CreateSpillStackObject. I think you may be fixing the wrong bug. Even if not silently disabling all optimization for existing callers is not acceptable.

I'm not quite sure that's right: Some ABIs have fixed-offset spill slots (e.g. PowerPC). Calling a spill slot immutable seems odd anyway, given that, by definition, you store into it. Also, they have isAliased == false regardless.

Hal, I think we have a terminology problem here. To me a "spill slot" is one created by the register allocator when spilling vregs. Are you saying that PowerPC has preassigned offsets which the register allocator must use? Or are you referring to something else entirely?

kparzysz added a comment.EditedAug 30 2016, 4:15 PM

In the same header:
/// Create a new statically sized stack object that represents a spill slot,

/// returning a nonnegative identifier to represent it.
int CreateSpillStackObject(uint64_t Size, unsigned Alignment);

That same header has

/// Create a spill slot at a fixed location on the stack.
/// Returns an index with a negative value.
int CreateFixedSpillStackObject(uint64_t Size, int64_t SPOffset);

My point is that while *spill slots* are clearly not immutable, there are other stack slots created by the same interface you modified which are. Disabling optimization of those slots is clearly not okay.

Spill slot is a stack slot that is not aliased to anything else. Fixed spill slot is a spill slot with a specified offset (i.e. its position in the frame is fixed).

Edit: My change modifies the CreateFixedSpillStackObject. It affects a subset of all spill slots, not even all of them: the inclusion that your concern states is reversed.

At least per documentation, spill slots should be created via CreateSpillStackObject. I think you may be fixing the wrong bug. Even if not silently disabling all optimization for existing callers is not acceptable.

I'm not quite sure that's right: Some ABIs have fixed-offset spill slots (e.g. PowerPC). Calling a spill slot immutable seems odd anyway, given that, by definition, you store into it. Also, they have isAliased == false regardless.

Hal, I think we have a terminology problem here. To me a "spill slot" is one created by the register allocator when spilling vregs. Are you saying that PowerPC has preassigned offsets which the register allocator must use? Or are you referring to something else entirely?

Fair enough. Yes, PowerPC has these, for callee-saved-register saving, and CreateFixedSpillStackObject is not used for those. CreateFixedSpillStackObject is only used by Hexagon and by x86. x86 uses this function in X86FrameLowering::assignCalleeSavedSpillSlots for assigning CSR spill slots. Hexagon seems to do the same (in HexagonFrameLowering::assignCalleeSavedSpillSlots).

My understanding is that this matters only when you have post-RA scheduling. Without post-RA scheduling, these slots are "effectively immutable", since they're stored to in the prologue and loaded in the epilogue, and that code isn't re-scheduled. With post-RA scheduling, this code might be re-scheduled, and it is important to actually consider whether the stores in the prologue might write to the slots being read by the epilogue code. This consideration won't happen if the slot is "immutable" (because, if it is immutable, then the store must be irrelevant). Krzysztof, did I understand the situation correctly?

If my understanding is correct, this seems like the right fix. It seems unlikely to affect performance on targets other than Hexagon and non-server-class x86 cores (i.e. Atom) where post-RA scheduling might be enabled.

In the same header:
/// Create a new statically sized stack object that represents a spill slot,

/// returning a nonnegative identifier to represent it.
int CreateSpillStackObject(uint64_t Size, unsigned Alignment);

That same header has

/// Create a spill slot at a fixed location on the stack.
/// Returns an index with a negative value.
int CreateFixedSpillStackObject(uint64_t Size, int64_t SPOffset);

My point is that while *spill slots* are clearly not immutable, there are other stack slots created by the same interface you modified which are. Disabling optimization of those slots is clearly not okay.

Spill slot is a stack slot that is not aliased to anything else. Fixed spill slot is a spill slot with a specified offset (i.e. its position in the frame is fixed).

Gah! I reread your patch and realized I'd misread it originally. I thought you were changing "CreateFixedObject" not "CreateFixedSpillStackObject". All of my comments are off base, apologies for misleading the discussion.

hfinkel accepted this revision.Aug 30 2016, 4:20 PM
hfinkel edited edge metadata.

In the same header:
/// Create a new statically sized stack object that represents a spill slot,

/// returning a nonnegative identifier to represent it.
int CreateSpillStackObject(uint64_t Size, unsigned Alignment);

That same header has

/// Create a spill slot at a fixed location on the stack.
/// Returns an index with a negative value.
int CreateFixedSpillStackObject(uint64_t Size, int64_t SPOffset);

My point is that while *spill slots* are clearly not immutable, there are other stack slots created by the same interface you modified which are. Disabling optimization of those slots is clearly not okay.

Spill slot is a stack slot that is not aliased to anything else. Fixed spill slot is a spill slot with a specified offset (i.e. its position in the frame is fixed).

Gah! I reread your patch and realized I'd misread it originally. I thought you were changing "CreateFixedObject" not "CreateFixedSpillStackObject". All of my comments are off base, apologies for misleading the discussion.

Good ;) -- In that case, this LGTM.

At least per documentation, spill slots should be created via CreateSpillStackObject. I think you may be fixing the wrong bug. Even if not silently disabling all optimization for existing callers is not acceptable.

I'm not quite sure that's right: Some ABIs have fixed-offset spill slots (e.g. PowerPC). Calling a spill slot immutable seems odd anyway, given that, by definition, you store into it. Also, they have isAliased == false regardless.

Hal, I think we have a terminology problem here. To me a "spill slot" is one created by the register allocator when spilling vregs. Are you saying that PowerPC has preassigned offsets which the register allocator must use? Or are you referring to something else entirely?

Fair enough. Yes, PowerPC has these, for callee-saved-register saving, and CreateFixedSpillStackObject is not used for those. CreateFixedSpillStackObject is only used by Hexagon and by x86. x86 uses this function in X86FrameLowering::assignCalleeSavedSpillSlots for assigning CSR spill slots. Hexagon seems to do the same (in HexagonFrameLowering::assignCalleeSavedSpillSlots).

My understanding is that this matters only when you have post-RA scheduling. Without post-RA scheduling, these slots are "effectively immutable", since they're stored to in the prologue and loaded in the epilogue, and that code isn't re-scheduled. With post-RA scheduling, this code might be re-scheduled, and it is important to actually consider whether the stores in the prologue might write to the slots being read by the epilogue code. This consideration won't happen if the slot is "immutable" (because, if it is immutable, then the store must be irrelevant). Krzysztof, did I understand the situation correctly?

If my understanding is correct, this seems like the right fix. It seems unlikely to affect performance on targets other than Hexagon and non-server-class x86 cores (i.e. Atom) where post-RA scheduling might be enabled.

Hal, thanks for the context. As I replied separately, I'd misread the change, but your explanation provided a good amount of context which is great to understand anyways.

Gah! I reread your patch and realized I'd misread it originally. I thought you were changing "CreateFixedObject" not "CreateFixedSpillStackObject". All of my comments are off base, apologies for misleading the discussion.

No problem. :)

Krzysztof, did I understand the situation correctly?

Yes, exactly. I'd only add that the problem can also occur during packetization (as a matter of fact, that's where I discovered it).

This revision was automatically updated to reflect the committed changes.

Committed in r280244.