264 lines
11 KiB
Diff
264 lines
11 KiB
Diff
Pull in r202930 from upstream llvm trunk (by Hans Wennborg):
|
|
|
|
Check for dynamic allocas and inline asm that clobbers sp before building
|
|
selection dag (PR19012)
|
|
|
|
In X86SelectionDagInfo::EmitTargetCodeForMemcpy we check with MachineFrameInfo
|
|
to make sure that ESI isn't used as a base pointer register before we choose to
|
|
emit rep movs (which clobbers esi).
|
|
|
|
The problem is that MachineFrameInfo wouldn't know about dynamic allocas or
|
|
inline asm that clobbers the stack pointer until SelectionDAGBuilder has
|
|
encountered them.
|
|
|
|
This patch fixes the problem by checking for such things when building the
|
|
FunctionLoweringInfo.
|
|
|
|
Differential Revision: http://llvm-reviews.chandlerc.com/D2954
|
|
|
|
Introduced here: http://svnweb.freebsd.org/changeset/base/263312
|
|
|
|
Index: lib/CodeGen/MachineFunction.cpp
|
|
===================================================================
|
|
--- lib/CodeGen/MachineFunction.cpp
|
|
+++ lib/CodeGen/MachineFunction.cpp
|
|
@@ -525,13 +525,14 @@ int MachineFrameInfo::CreateSpillStackObject(uint6
|
|
/// variable sized object is created, whether or not the index returned is
|
|
/// actually used.
|
|
///
|
|
-int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment) {
|
|
+int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment,
|
|
+ const AllocaInst *Alloca) {
|
|
HasVarSizedObjects = true;
|
|
Alignment =
|
|
clampStackAlignment(!getFrameLowering()->isStackRealignable() ||
|
|
!RealignOption,
|
|
Alignment, getFrameLowering()->getStackAlignment());
|
|
- Objects.push_back(StackObject(0, Alignment, 0, false, false, true, 0));
|
|
+ Objects.push_back(StackObject(0, Alignment, 0, false, false, true, Alloca));
|
|
ensureMaxAlignment(Alignment);
|
|
return (int)Objects.size()-NumFixedObjects-1;
|
|
}
|
|
Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
|
|
===================================================================
|
|
--- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
|
|
+++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
|
|
@@ -419,7 +419,7 @@ bool SelectionDAGISel::runOnMachineFunction(Machin
|
|
SplitCriticalSideEffectEdges(const_cast<Function&>(Fn), this);
|
|
|
|
CurDAG->init(*MF, TTI, TLI);
|
|
- FuncInfo->set(Fn, *MF);
|
|
+ FuncInfo->set(Fn, *MF, CurDAG);
|
|
|
|
if (UseMBPI && OptLevel != CodeGenOpt::None)
|
|
FuncInfo->BPI = &getAnalysis<BranchProbabilityInfo>();
|
|
@@ -429,7 +429,6 @@ bool SelectionDAGISel::runOnMachineFunction(Machin
|
|
SDB->init(GFI, *AA, LibInfo);
|
|
|
|
MF->setHasInlineAsm(false);
|
|
- MF->getFrameInfo()->setHasInlineAsmWithSPAdjust(false);
|
|
|
|
SelectAllBasicBlocks(Fn);
|
|
|
|
Index: lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
|
|
===================================================================
|
|
--- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
|
|
+++ lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
|
|
@@ -33,6 +33,7 @@
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
+#include "llvm/Target/TargetFrameLowering.h"
|
|
#include "llvm/Target/TargetLowering.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
#include "llvm/Target/TargetRegisterInfo.h"
|
|
@@ -55,7 +56,8 @@ static bool isUsedOutsideOfDefiningBlock(const Ins
|
|
return false;
|
|
}
|
|
|
|
-void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf) {
|
|
+void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
|
+ SelectionDAG *DAG) {
|
|
const TargetLowering *TLI = TM.getTargetLowering();
|
|
|
|
Fn = &fn;
|
|
@@ -100,6 +102,43 @@ static bool isUsedOutsideOfDefiningBlock(const Ins
|
|
for (; BB != EB; ++BB)
|
|
for (BasicBlock::const_iterator I = BB->begin(), E = BB->end();
|
|
I != E; ++I) {
|
|
+ // Look for dynamic allocas.
|
|
+ if (const AllocaInst *AI = dyn_cast<AllocaInst>(I)) {
|
|
+ if (!AI->isStaticAlloca()) {
|
|
+ unsigned Align = std::max(
|
|
+ (unsigned)TLI->getDataLayout()->getPrefTypeAlignment(
|
|
+ AI->getAllocatedType()),
|
|
+ AI->getAlignment());
|
|
+ unsigned StackAlign = TM.getFrameLowering()->getStackAlignment();
|
|
+ if (Align <= StackAlign)
|
|
+ Align = 0;
|
|
+ // Inform the Frame Information that we have variable-sized objects.
|
|
+ MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1, AI);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Look for inline asm that clobbers the SP register.
|
|
+ if (isa<CallInst>(I) || isa<InvokeInst>(I)) {
|
|
+ ImmutableCallSite CS(I);
|
|
+ if (const InlineAsm *IA = dyn_cast<InlineAsm>(CS.getCalledValue())) {
|
|
+ unsigned SP = TLI->getStackPointerRegisterToSaveRestore();
|
|
+ std::vector<TargetLowering::AsmOperandInfo> Ops =
|
|
+ TLI->ParseConstraints(CS);
|
|
+ for (size_t I = 0, E = Ops.size(); I != E; ++I) {
|
|
+ TargetLowering::AsmOperandInfo &Op = Ops[I];
|
|
+ if (Op.Type == InlineAsm::isClobber) {
|
|
+ // Clobbers don't have SDValue operands, hence SDValue().
|
|
+ TLI->ComputeConstraintToUse(Op, SDValue(), DAG);
|
|
+ std::pair<unsigned, const TargetRegisterClass*> PhysReg =
|
|
+ TLI->getRegForInlineAsmConstraint(Op.ConstraintCode,
|
|
+ Op.ConstraintVT);
|
|
+ if (PhysReg.first == SP)
|
|
+ MF->getFrameInfo()->setHasInlineAsmWithSPAdjust(true);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
// Mark values used outside their block as exported, by allocating
|
|
// a virtual register for them.
|
|
if (isUsedOutsideOfDefiningBlock(I))
|
|
Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
|
|
===================================================================
|
|
--- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
|
|
+++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
|
|
@@ -860,10 +860,10 @@ void RegsForValue::AddInlineAsmOperands(unsigned C
|
|
unsigned TheReg = Regs[Reg++];
|
|
Ops.push_back(DAG.getRegister(TheReg, RegisterVT));
|
|
|
|
- // Notice if we clobbered the stack pointer. Yes, inline asm can do this.
|
|
if (TheReg == SP && Code == InlineAsm::Kind_Clobber) {
|
|
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
|
- MFI->setHasInlineAsmWithSPAdjust(true);
|
|
+ // If we clobbered the stack pointer, MFI should know about it.
|
|
+ assert(DAG.getMachineFunction().getFrameInfo()->
|
|
+ hasInlineAsmWithSPAdjust());
|
|
}
|
|
}
|
|
}
|
|
@@ -3378,9 +3378,7 @@ void SelectionDAGBuilder::visitAlloca(const Alloca
|
|
setValue(&I, DSA);
|
|
DAG.setRoot(DSA.getValue(1));
|
|
|
|
- // Inform the Frame Information that we have just allocated a variable-sized
|
|
- // object.
|
|
- FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1);
|
|
+ assert(FuncInfo.MF->getFrameInfo()->hasVarSizedObjects());
|
|
}
|
|
|
|
void SelectionDAGBuilder::visitLoad(const LoadInst &I) {
|
|
Index: test/CodeGen/X86/stack-align-memcpy.ll
|
|
===================================================================
|
|
--- test/CodeGen/X86/stack-align-memcpy.ll
|
|
+++ test/CodeGen/X86/stack-align-memcpy.ll
|
|
@@ -2,6 +2,9 @@
|
|
|
|
%struct.foo = type { [88 x i8] }
|
|
|
|
+declare void @bar(i8* nocapture, %struct.foo* align 4 byval) nounwind
|
|
+declare void @baz(i8*) nounwind
|
|
+
|
|
; PR15249
|
|
; We can't use rep;movsl here because it clobbers the base pointer in %esi.
|
|
define void @test1(%struct.foo* nocapture %x, i32 %y) nounwind {
|
|
@@ -15,4 +18,26 @@ define void @test1(%struct.foo* nocapture %x, i32
|
|
; CHECK-NOT: rep;movsl
|
|
}
|
|
|
|
-declare void @bar(i8* nocapture, %struct.foo* align 4 byval) nounwind
|
|
+; PR19012
|
|
+; Also don't clobber %esi if the dynamic alloca comes after the memcpy.
|
|
+define void @test2(%struct.foo* nocapture %x, i32 %y, i8* %z) nounwind {
|
|
+ call void @bar(i8* %z, %struct.foo* align 4 byval %x)
|
|
+ %dynalloc = alloca i8, i32 %y, align 1
|
|
+ call void @baz(i8* %dynalloc)
|
|
+ ret void
|
|
+
|
|
+; CHECK-LABEL: test2:
|
|
+; CHECK: movl %esp, %esi
|
|
+; CHECK-NOT: rep;movsl
|
|
+}
|
|
+
|
|
+; Check that we do use rep movs if we make the alloca static.
|
|
+define void @test3(%struct.foo* nocapture %x, i32 %y, i8* %z) nounwind {
|
|
+ call void @bar(i8* %z, %struct.foo* align 4 byval %x)
|
|
+ %statalloc = alloca i8, i32 8, align 1
|
|
+ call void @baz(i8* %statalloc)
|
|
+ ret void
|
|
+
|
|
+; CHECK-LABEL: test3:
|
|
+; CHECK: rep;movsl
|
|
+}
|
|
Index: test/CodeGen/X86/inline-asm-sp-clobber-memcpy.ll
|
|
===================================================================
|
|
--- test/CodeGen/X86/inline-asm-sp-clobber-memcpy.ll
|
|
+++ test/CodeGen/X86/inline-asm-sp-clobber-memcpy.ll
|
|
@@ -0,0 +1,17 @@
|
|
+; RUN: llc < %s -force-align-stack -mtriple i386-apple-darwin -mcpu=i486 | FileCheck %s
|
|
+
|
|
+%struct.foo = type { [88 x i8] }
|
|
+
|
|
+declare void @bar(i8* nocapture, %struct.foo* align 4 byval) nounwind
|
|
+
|
|
+; PR19012
|
|
+; Don't clobber %esi if we have inline asm that clobbers %esp.
|
|
+define void @test1(%struct.foo* nocapture %x, i32 %y, i8* %z) nounwind {
|
|
+ call void @bar(i8* %z, %struct.foo* align 4 byval %x)
|
|
+ call void asm sideeffect inteldialect "xor esp, esp", "=*m,~{flags},~{esp},~{esp},~{dirflag},~{fpsr},~{flags}"(i8* %z)
|
|
+ ret void
|
|
+
|
|
+; CHECK-LABEL: test1:
|
|
+; CHECK: movl %esp, %esi
|
|
+; CHECK-NOT: rep;movsl
|
|
+}
|
|
Index: include/llvm/CodeGen/FunctionLoweringInfo.h
|
|
===================================================================
|
|
--- include/llvm/CodeGen/FunctionLoweringInfo.h
|
|
+++ include/llvm/CodeGen/FunctionLoweringInfo.h
|
|
@@ -41,6 +41,7 @@ class MachineBasicBlock;
|
|
class MachineFunction;
|
|
class MachineModuleInfo;
|
|
class MachineRegisterInfo;
|
|
+class SelectionDAG;
|
|
class TargetLowering;
|
|
class Value;
|
|
|
|
@@ -125,7 +126,7 @@ class FunctionLoweringInfo {
|
|
/// set - Initialize this FunctionLoweringInfo with the given Function
|
|
/// and its associated MachineFunction.
|
|
///
|
|
- void set(const Function &Fn, MachineFunction &MF);
|
|
+ void set(const Function &Fn, MachineFunction &MF, SelectionDAG *DAG);
|
|
|
|
/// clear - Clear out all the function-specific state. This returns this
|
|
/// FunctionLoweringInfo to an empty state, ready to be used for a
|
|
Index: include/llvm/CodeGen/MachineFrameInfo.h
|
|
===================================================================
|
|
--- include/llvm/CodeGen/MachineFrameInfo.h
|
|
+++ include/llvm/CodeGen/MachineFrameInfo.h
|
|
@@ -244,6 +244,7 @@ class MachineFrameInfo {
|
|
LocalFrameSize = 0;
|
|
LocalFrameMaxAlign = 0;
|
|
UseLocalStackAllocationBlock = false;
|
|
+ HasInlineAsmWithSPAdjust = false;
|
|
}
|
|
|
|
/// hasStackObjects - Return true if there are any stack objects in this
|
|
@@ -529,7 +530,7 @@ class MachineFrameInfo {
|
|
/// variable sized object is created, whether or not the index returned is
|
|
/// actually used.
|
|
///
|
|
- int CreateVariableSizedObject(unsigned Alignment);
|
|
+ int CreateVariableSizedObject(unsigned Alignment, const AllocaInst *Alloca);
|
|
|
|
/// getCalleeSavedInfo - Returns a reference to call saved info vector for the
|
|
/// current function.
|