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 TargetInstrInfo &TII;
const TargetLowering &TLI; const TargetLowering &TLI;
const TargetRegisterInfo &TRI; 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; 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: public:
/// getLastLocalValue - Return the position of the last instruction /// getLastLocalValue - Return the position of the last instruction
/// emitted for materializing constants for use in the current block. /// emitted for materializing constants for use in the current block.
@ -63,7 +73,10 @@ public:
/// setLastLocalValue - Update the position of the last instruction /// setLastLocalValue - Update the position of the last instruction
/// emitted for materializing constants for use in the current block. /// 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 /// startNewBlock - Set the current block to which generated machine
/// instructions will be appended, and clear the local CSE map. /// instructions will be appended, and clear the local CSE map.
@ -358,6 +371,11 @@ private:
/// be materialized with new instructions. /// be materialized with new instructions.
unsigned materializeRegForValue(const Value *V, MVT VT); 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. /// hasTrivialKill - Test whether the given value has exactly one use.
bool hasTrivialKill(const Value *V) const; bool hasTrivialKill(const Value *V) const;
}; };

View File

@ -66,17 +66,22 @@ using namespace llvm;
void FastISel::startNewBlock() { void FastISel::startNewBlock() {
LocalValueMap.clear(); LocalValueMap.clear();
// Start out as null, meaining no local-value instructions have EmitStartPt = 0;
// been emitted.
LastLocalValue = 0;
// Advance the last local value past any EH_LABEL instructions. // Advance the emit start point past any EH_LABEL instructions.
MachineBasicBlock::iterator MachineBasicBlock::iterator
I = FuncInfo.MBB->begin(), E = FuncInfo.MBB->end(); I = FuncInfo.MBB->begin(), E = FuncInfo.MBB->end();
while (I != E && I->getOpcode() == TargetOpcode::EH_LABEL) { while (I != E && I->getOpcode() == TargetOpcode::EH_LABEL) {
LastLocalValue = I; EmitStartPt = I;
++I; ++I;
} }
LastLocalValue = EmitStartPt;
}
void FastISel::flushLocalValueMap() {
LocalValueMap.clear();
LastLocalValue = EmitStartPt;
recomputeInsertPt();
} }
bool FastISel::hasTrivialKill(const Value *V) const { 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. // An arbitrary call. Bail.
return false; return false;
} }

View File

@ -1,5 +1,5 @@
; RUN: llc -O0 < %s | FileCheck %s ; RUN: llc -O0 < %s | FileCheck %s
; CHECK: @DEBUG_VALUE: mydata <- [sp+#8]+#0 ; CHECK: @DEBUG_VALUE: mydata <- [sp+#4]+#0
; Radar 9331779 ; 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 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" target triple = "thumbv7-apple-macosx10.7.0"

View File

@ -259,4 +259,27 @@ define void @test21(double* %p1) {
; CHECK: test21: ; CHECK: test21:
; CHECK-NOT: pxor ; CHECK-NOT: pxor
; CHECK: movsd LCPI ; 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)