Avoid extra vreg copies for arguments passed in registers. Specifically, this can make MachineCSE more effective in some cases (especially in small functions). PR8361 / part of rdar://problem/8259436 .

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@130928 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eli Friedman 2011-05-05 16:53:34 +00:00
parent d41bd043d3
commit 23d3243e62
4 changed files with 65 additions and 38 deletions

View File

@ -54,25 +54,6 @@ static bool isUsedOutsideOfDefiningBlock(const Instruction *I) {
return false; return false;
} }
/// isOnlyUsedInEntryBlock - If the specified argument is only used in the
/// entry block, return true. This includes arguments used by switches, since
/// the switch may expand into multiple basic blocks.
static bool isOnlyUsedInEntryBlock(const Argument *A, bool EnableFastISel) {
// With FastISel active, we may be splitting blocks, so force creation
// of virtual registers for all non-dead arguments.
if (EnableFastISel)
return A->use_empty();
const BasicBlock *Entry = A->getParent()->begin();
for (Value::const_use_iterator UI = A->use_begin(), E = A->use_end();
UI != E; ++UI) {
const User *U = *UI;
if (cast<Instruction>(U)->getParent() != Entry || isa<SwitchInst>(U))
return false; // Use not in entry block.
}
return true;
}
FunctionLoweringInfo::FunctionLoweringInfo(const TargetLowering &tli) FunctionLoweringInfo::FunctionLoweringInfo(const TargetLowering &tli)
: TLI(tli) { : TLI(tli) {
} }
@ -89,13 +70,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf) {
CanLowerReturn = TLI.CanLowerReturn(Fn->getCallingConv(), Fn->isVarArg(), CanLowerReturn = TLI.CanLowerReturn(Fn->getCallingConv(), Fn->isVarArg(),
Outs, Fn->getContext()); Outs, Fn->getContext());
// Create a vreg for each argument register that is not dead and is used
// outside of the entry block for the function.
for (Function::const_arg_iterator AI = Fn->arg_begin(), E = Fn->arg_end();
AI != E; ++AI)
if (!isOnlyUsedInEntryBlock(AI, EnableFastISel))
InitializeRegForValue(AI);
// Initialize the mapping of values to registers. This is only set up for // Initialize the mapping of values to registers. This is only set up for
// instruction values that are used outside of the block that defines // instruction values that are used outside of the block that defines
// them. // them.

View File

@ -6232,6 +6232,25 @@ SelectionDAGBuilder::CopyValueToVirtualRegister(const Value *V, unsigned Reg) {
#include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/SelectionDAGISel.h"
/// isOnlyUsedInEntryBlock - If the specified argument is only used in the
/// entry block, return true. This includes arguments used by switches, since
/// the switch may expand into multiple basic blocks.
static bool isOnlyUsedInEntryBlock(const Argument *A) {
// With FastISel active, we may be splitting blocks, so force creation
// of virtual registers for all non-dead arguments.
if (EnableFastISel)
return A->use_empty();
const BasicBlock *Entry = A->getParent()->begin();
for (Value::const_use_iterator UI = A->use_begin(), E = A->use_end();
UI != E; ++UI) {
const User *U = *UI;
if (cast<Instruction>(U)->getParent() != Entry || isa<SwitchInst>(U))
return false; // Use not in entry block.
}
return true;
}
void SelectionDAGISel::LowerArguments(const BasicBlock *LLVMBB) { void SelectionDAGISel::LowerArguments(const BasicBlock *LLVMBB) {
// If this is the entry block, emit arguments. // If this is the entry block, emit arguments.
const Function &F = *LLVMBB->getParent(); const Function &F = *LLVMBB->getParent();
@ -6375,8 +6394,8 @@ void SelectionDAGISel::LowerArguments(const BasicBlock *LLVMBB) {
if (I->use_empty() && NumValues) if (I->use_empty() && NumValues)
SDB->setUnusedArgValue(I, InVals[i]); SDB->setUnusedArgValue(I, InVals[i]);
for (unsigned Value = 0; Value != NumValues; ++Value) { for (unsigned Val = 0; Val != NumValues; ++Val) {
EVT VT = ValueVTs[Value]; EVT VT = ValueVTs[Val];
EVT PartVT = TLI.getRegisterType(*CurDAG->getContext(), VT); EVT PartVT = TLI.getRegisterType(*CurDAG->getContext(), VT);
unsigned NumParts = TLI.getNumRegisters(*CurDAG->getContext(), VT); unsigned NumParts = TLI.getNumRegisters(*CurDAG->getContext(), VT);
@ -6395,21 +6414,34 @@ void SelectionDAGISel::LowerArguments(const BasicBlock *LLVMBB) {
i += NumParts; i += NumParts;
} }
// We don't need to do anything else for unused arguments.
if (ArgValues.empty())
continue;
// Note down frame index for byval arguments. // Note down frame index for byval arguments.
if (I->hasByValAttr() && !ArgValues.empty()) if (I->hasByValAttr())
if (FrameIndexSDNode *FI = if (FrameIndexSDNode *FI =
dyn_cast<FrameIndexSDNode>(ArgValues[0].getNode())) dyn_cast<FrameIndexSDNode>(ArgValues[0].getNode()))
FuncInfo->setByValArgumentFrameIndex(I, FI->getIndex()); FuncInfo->setByValArgumentFrameIndex(I, FI->getIndex());
if (!I->use_empty()) { SDValue Res = DAG.getMergeValues(&ArgValues[0], NumValues,
SDValue Res; SDB->getCurDebugLoc());
if (!ArgValues.empty()) SDB->setValue(I, Res);
Res = DAG.getMergeValues(&ArgValues[0], NumValues,
SDB->getCurDebugLoc());
SDB->setValue(I, Res);
// If this argument is live outside of the entry block, insert a copy from // If this argument is live outside of the entry block, insert a copy from
// wherever we got it to the vreg that other BB's will reference it as. // wherever we got it to the vreg that other BB's will reference it as.
if (Res.getOpcode() == ISD::CopyFromReg) {
// If we can, though, try to skip creating an unnecessary vreg.
// FIXME: This isn't very clean... it would be nice to make this more
// general.
unsigned Reg = cast<RegisterSDNode>(Res.getOperand(1))->getReg();
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
FuncInfo->ValueMap[I] = Reg;
continue;
}
}
if (!isOnlyUsedInEntryBlock(I)) {
FuncInfo->InitializeRegForValue(I);
SDB->CopyToExportRegsIfNeeded(I); SDB->CopyToExportRegsIfNeeded(I);
} }
} }

View File

@ -22,7 +22,7 @@ bb:
; it is. ; it is.
; ;
; CHECK: # %bb ; CHECK: # %bb
; CHECK: addq $64036, %rdi ; CHECK: leaq 64036(%rdx), %rdi
; CHECK: rep;stosl ; CHECK: rep;stosl
%tmp5 = bitcast i32* %tmp4 to i8* %tmp5 = bitcast i32* %tmp4 to i8*

View File

@ -9,6 +9,27 @@ entry:
; CHECK: cmp: ; CHECK: cmp:
; CHECK: cmpl ; CHECK: cmpl
; CHECK: jg ; CHECK: jg
if.end: ; preds = %entry
; CHECK-NOT: cmpl
; CHECK: cmov
%cmp4 = icmp slt i32 %a, %b
%. = select i1 %cmp4, i32 2, i32 111
br label %return
return: ; preds = %if.end, %entry
%retval.0 = phi i32 [ 1, %entry ], [ %., %if.end ]
ret i32 %retval.0
}
define i32 @cmp2(i32 %a, i32 %b) nounwind readnone ssp {
entry:
%cmp = icmp sgt i32 %a, %b
br i1 %cmp, label %return, label %if.end
; CHECK: cmp2:
; CHECK: cmpl
; CHECK: jg
if.end: ; preds = %entry if.end: ; preds = %entry
; CHECK-NOT: cmpl ; CHECK-NOT: cmpl
; CHECK: cmov ; CHECK: cmov