mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-31 10:34:17 +00:00
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:
parent
d41bd043d3
commit
23d3243e62
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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*
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user