FastISel: avoid function calls between the materialization of the constant and its use.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@137993 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ivan Krasin 2011-08-18 22:06:10 +00:00
parent 93b3eff623
commit 74af88a666
4 changed files with 64 additions and 8 deletions

View File

@ -54,8 +54,18 @@ protected:
const TargetInstrInfo &TII;
const TargetLowering &TLI;
const TargetRegisterInfo &TRI;
/// The position of the last instruction for materializing constants
/// for use in the current block. It resets to EmitStartPt when it
/// makes sense (for example, it's usually profitable to avoid function
/// calls between the definition and the use)
MachineInstr *LastLocalValue;
/// The top most instruction in the current block that is allowed for
/// emitting local variables. LastLocalValue resets to EmitStartPt when
/// it makes sense (for example, on function calls)
MachineInstr *EmitStartPt;
public:
/// getLastLocalValue - Return the position of the last instruction
/// emitted for materializing constants for use in the current block.
@ -63,7 +73,10 @@ public:
/// setLastLocalValue - Update the position of the last instruction
/// emitted for materializing constants for use in the current block.
void setLastLocalValue(MachineInstr *I) { LastLocalValue = I; }
void setLastLocalValue(MachineInstr *I) {
EmitStartPt = I;
LastLocalValue = I;
}
/// startNewBlock - Set the current block to which generated machine
/// instructions will be appended, and clear the local CSE map.
@ -358,6 +371,11 @@ private:
/// be materialized with new instructions.
unsigned materializeRegForValue(const Value *V, MVT VT);
/// flushLocalValueMap - clears LocalValueMap and moves the area for the
/// new local variables to the beginning of the block. It helps to avoid
/// spilling cached variables across heavy instructions like calls.
void flushLocalValueMap();
/// hasTrivialKill - Test whether the given value has exactly one use.
bool hasTrivialKill(const Value *V) const;
};

View File

@ -66,17 +66,22 @@ using namespace llvm;
void FastISel::startNewBlock() {
LocalValueMap.clear();
// Start out as null, meaining no local-value instructions have
// been emitted.
LastLocalValue = 0;
EmitStartPt = 0;
// Advance the last local value past any EH_LABEL instructions.
// Advance the emit start point past any EH_LABEL instructions.
MachineBasicBlock::iterator
I = FuncInfo.MBB->begin(), E = FuncInfo.MBB->end();
while (I != E && I->getOpcode() == TargetOpcode::EH_LABEL) {
LastLocalValue = I;
EmitStartPt = I;
++I;
}
LastLocalValue = EmitStartPt;
}
void FastISel::flushLocalValueMap() {
LocalValueMap.clear();
LastLocalValue = EmitStartPt;
recomputeInsertPt();
}
bool FastISel::hasTrivialKill(const Value *V) const {
@ -645,6 +650,16 @@ bool FastISel::SelectCall(const User *I) {
}
}
// Usually, it does not make sense to initialize a value,
// make an unrelated function call and use the value, because
// it tends to be spilled on the stack. So, we move the pointer
// to the last local value to the beginning of the block, so that
// all the values which have already been materialized,
// appear after the call. It also makes sense to skip intrinsics
// since they tend to be inlined.
if (!isa<IntrinsicInst>(F))
flushLocalValueMap();
// An arbitrary call. Bail.
return false;
}

View File

@ -1,5 +1,5 @@
; RUN: llc -O0 < %s | FileCheck %s
; CHECK: @DEBUG_VALUE: mydata <- [sp+#8]+#0
; CHECK: @DEBUG_VALUE: mydata <- [sp+#4]+#0
; Radar 9331779
target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32"
target triple = "thumbv7-apple-macosx10.7.0"

View File

@ -259,4 +259,27 @@ define void @test21(double* %p1) {
; CHECK: test21:
; CHECK-NOT: pxor
; CHECK: movsd LCPI
}
}
; Check that immediate arguments to a function
; do not cause massive spilling and are used
; as immediates just before the call.
define void @test22() nounwind {
entry:
call void @foo22(i32 0)
call void @foo22(i32 1)
call void @foo22(i32 2)
call void @foo22(i32 3)
ret void
; CHECK: test22:
; CHECK: movl $0, %edi
; CHECK: callq _foo22
; CHECK: movl $1, %edi
; CHECK: callq _foo22
; CHECK: movl $2, %edi
; CHECK: callq _foo22
; CHECK: movl $3, %edi
; CHECK: callq _foo22
}
declare void @foo22(i32)