------------------------------------------------------------------------
r257730 | majnemer | 2016-01-13 17:20:03 -0800 (Wed, 13 Jan 2016) | 11 lines
[X86] Don't alter HasOpaqueSPAdjustment after we've relied on it
We rely on HasOpaqueSPAdjustment not changing after we've calculated
things based on it. Things like whether or not we can use 'rep;movs' to
copy bytes around, that sort of thing. If it changes, invariants in the
backend will quietly break. This situation arose when we had a call to
memcpy *and* a COPY of the FLAGS register where we would attempt to
reference local variables using %esi, a register that was clobbered by
the 'rep;movs'.
This fixes PR26124.
------------------------------------------------------------------------
git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_38@257779
91177308-0d34-0410-b5e6-
96231b3b80d8
/// opaque mechanism like inline assembly or Win32 EH.
bool HasOpaqueSPAdjustment;
+ /// True if the function contains operations which will lower down to
+ /// instructions which manipulate the stack pointer.
+ bool HasCopyImplyingStackAdjustment;
+
/// True if the function contains a call to the llvm.vastart intrinsic.
bool HasVAStart;
LocalFrameMaxAlign = 0;
UseLocalStackAllocationBlock = false;
HasOpaqueSPAdjustment = false;
+ HasCopyImplyingStackAdjustment = false;
HasVAStart = false;
HasMustTailInVarArgFunc = false;
Save = nullptr;
bool hasOpaqueSPAdjustment() const { return HasOpaqueSPAdjustment; }
void setHasOpaqueSPAdjustment(bool B) { HasOpaqueSPAdjustment = B; }
+ /// Returns true if the function contains operations which will lower down to
+ /// instructions which manipulate the stack pointer.
+ bool hasCopyImplyingStackAdjustment() const {
+ return HasCopyImplyingStackAdjustment;
+ }
+ void setHasCopyImplyingStackAdjustment(bool B) {
+ HasCopyImplyingStackAdjustment = B;
+ }
+
/// Returns true if the function calls the llvm.va_start intrinsic.
bool hasVAStart() const { return HasVAStart; }
void setHasVAStart(bool B) { HasVAStart = B; }
}
/// Return true if the MachineFunction contains a COPY which would imply
- /// HasOpaqueSPAdjustment.
+ /// HasCopyImplyingStackAdjustment.
virtual bool hasCopyImplyingStackAdjustment(MachineFunction *MF) const {
return false;
}
}
if (TLI->hasCopyImplyingStackAdjustment(MF))
- MFI->setHasOpaqueSPAdjustment(true);
+ MFI->setHasCopyImplyingStackAdjustment(true);
// Freeze the set of reserved registers now that MachineFrameInfo has been
// set up. All the information required by getReservedRegs() should be
MFI->isFrameAddressTaken() || MFI->hasOpaqueSPAdjustment() ||
MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer() ||
MMI.callsUnwindInit() || MMI.hasEHFunclets() || MMI.callsEHReturn() ||
- MFI->hasStackMap() || MFI->hasPatchPoint());
+ MFI->hasStackMap() || MFI->hasPatchPoint() ||
+ MFI->hasCopyImplyingStackAdjustment());
}
static unsigned getSUBriOpcode(unsigned IsLP64, int64_t Imm) {
// push and pop from the stack.
if (Is64Bit && !Fn->hasFnAttribute(Attribute::NoRedZone) &&
!TRI->needsStackRealignment(MF) &&
- !MFI->hasVarSizedObjects() && // No dynamic alloca.
- !MFI->adjustsStack() && // No calls.
- !IsWin64CC && // Win64 has no Red Zone
- !MFI->hasOpaqueSPAdjustment() && // Don't push and pop.
- !MF.shouldSplitStack()) { // Regular stack
+ !MFI->hasVarSizedObjects() && // No dynamic alloca.
+ !MFI->adjustsStack() && // No calls.
+ !IsWin64CC && // Win64 has no Red Zone
+ !MFI->hasCopyImplyingStackAdjustment() && // Don't push and pop.
+ !MF.shouldSplitStack()) { // Regular stack
uint64_t MinSize = X86FI->getCalleeSavedFrameSize();
if (HasFP) MinSize += SlotSize;
StackSize = std::max(MinSize, StackSize > 128 ? StackSize - 128 : 0);
// We need a frame pointer because this will get lowered to a PUSH/POP
// sequence.
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setHasOpaqueSPAdjustment(true);
+ MFI->setHasCopyImplyingStackAdjustment(true);
// Don't do anything here, we will expand these intrinsics out later
// during ExpandISelPseudos in EmitInstrWithCustomInserter.
return SDValue();
--- /dev/null
+; RUN: llc < %s | FileCheck %s
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i686-pc-windows-msvc18.0.0"
+
+%struct.T = type { i64, [3 x i32] }
+
+; Function Attrs: nounwind optsize
+define void @f(i8* %p, i8* %q, i32* inalloca nocapture %unused) #0 {
+entry:
+ %g = alloca %struct.T, align 8
+ %r = alloca i32, align 8
+ store i32 0, i32* %r, align 4
+ call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 24, i32 8, i1 false)
+ br label %while.body
+
+while.body: ; preds = %while.body, %entry
+ %load = load i32, i32* %r, align 4
+ %dec = add nsw i32 %load, -1
+ store i32 %dec, i32* %r, align 4
+ call void @g(%struct.T* %g)
+ %tobool = icmp eq i32 %dec, 0
+ br i1 %tobool, label %while.end, label %while.body
+
+while.end: ; preds = %while.body
+ ret void
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #1
+
+declare void @g(%struct.T*)
+
+; CHECK-LABEL: _f:
+; CHECK: pushl %ebp
+; CHECK: movl %esp, %ebp
+; CHECK: andl $-8, %esp
+; CHECK-NOT: movl %esp, %esi
+; CHECK: rep;movsl
+; CHECK: leal 8(%esp), %esi
+
+; CHECK: decl (%esp)
+; CHECK: seto %al
+; CHECK: lahf
+; CHECK: movl %eax, %edi
+; CHECK: pushl %esi
+; CHECK: calll _g
+; CHECK: addl $4, %esp
+; CHECK: movl %edi, %eax
+; CHECK: addb $127, %al
+; CHECK: sahf
+
+attributes #0 = { nounwind optsize }
+attributes #1 = { argmemonly nounwind }