Make fast scheduler handle asm clobbers correctly.

PR 7882.  Follows suggestion by Amaury Pouly, thanks.

llvm-svn: 111306
This commit is contained in:
Dale Johannesen 2010-08-17 22:17:24 +00:00
parent beb71b315a
commit 16f96445c3
2 changed files with 70 additions and 21 deletions

View File

@ -13,6 +13,7 @@
#define DEBUG_TYPE "pre-RA-sched"
#include "ScheduleDAGSDNodes.h"
#include "llvm/InlineAsm.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Target/TargetRegisterInfo.h"
@ -432,6 +433,30 @@ static EVT getPhysicalRegisterVT(SDNode *N, unsigned Reg,
return N->getValueType(NumRes);
}
/// CheckForLiveRegDef - Return true and update live register vector if the
/// specified register def of the specified SUnit clobbers any "live" registers.
static bool CheckForLiveRegDef(SUnit *SU, unsigned Reg,
std::vector<SUnit*> &LiveRegDefs,
SmallSet<unsigned, 4> &RegAdded,
SmallVector<unsigned, 4> &LRegs,
const TargetRegisterInfo *TRI) {
bool Added = false;
if (LiveRegDefs[Reg] && LiveRegDefs[Reg] != SU) {
if (RegAdded.insert(Reg)) {
LRegs.push_back(Reg);
Added = true;
}
}
for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias)
if (LiveRegDefs[*Alias] && LiveRegDefs[*Alias] != SU) {
if (RegAdded.insert(*Alias)) {
LRegs.push_back(*Alias);
Added = true;
}
}
return Added;
}
/// DelayForLiveRegsBottomUp - Returns true if it is necessary to delay
/// scheduling of the given node to satisfy live physical register dependencies.
/// If the specific node is the last one that's available to schedule, do
@ -446,37 +471,44 @@ bool ScheduleDAGFast::DelayForLiveRegsBottomUp(SUnit *SU,
for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
I != E; ++I) {
if (I->isAssignedRegDep()) {
unsigned Reg = I->getReg();
if (LiveRegDefs[Reg] && LiveRegDefs[Reg] != I->getSUnit()) {
if (RegAdded.insert(Reg))
LRegs.push_back(Reg);
}
for (const unsigned *Alias = TRI->getAliasSet(Reg);
*Alias; ++Alias)
if (LiveRegDefs[*Alias] && LiveRegDefs[*Alias] != I->getSUnit()) {
if (RegAdded.insert(*Alias))
LRegs.push_back(*Alias);
}
CheckForLiveRegDef(I->getSUnit(), I->getReg(), LiveRegDefs,
RegAdded, LRegs, TRI);
}
}
for (SDNode *Node = SU->getNode(); Node; Node = Node->getFlaggedNode()) {
if (Node->getOpcode() == ISD::INLINEASM) {
// Inline asm can clobber physical defs.
unsigned NumOps = Node->getNumOperands();
if (Node->getOperand(NumOps-1).getValueType() == MVT::Flag)
--NumOps; // Ignore the flag operand.
for (unsigned i = InlineAsm::Op_FirstOperand; i != NumOps;) {
unsigned Flags =
cast<ConstantSDNode>(Node->getOperand(i))->getZExtValue();
unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
++i; // Skip the ID value.
if (InlineAsm::isRegDefKind(Flags) ||
InlineAsm::isRegDefEarlyClobberKind(Flags)) {
// Check for def of register or earlyclobber register.
for (; NumVals; --NumVals, ++i) {
unsigned Reg = cast<RegisterSDNode>(Node->getOperand(i))->getReg();
if (TargetRegisterInfo::isPhysicalRegister(Reg))
CheckForLiveRegDef(SU, Reg, LiveRegDefs, RegAdded, LRegs, TRI);
}
} else
i += NumVals;
}
continue;
}
if (!Node->isMachineOpcode())
continue;
const TargetInstrDesc &TID = TII->get(Node->getMachineOpcode());
if (!TID.ImplicitDefs)
continue;
for (const unsigned *Reg = TID.ImplicitDefs; *Reg; ++Reg) {
if (LiveRegDefs[*Reg] && LiveRegDefs[*Reg] != SU) {
if (RegAdded.insert(*Reg))
LRegs.push_back(*Reg);
}
for (const unsigned *Alias = TRI->getAliasSet(*Reg);
*Alias; ++Alias)
if (LiveRegDefs[*Alias] && LiveRegDefs[*Alias] != SU) {
if (RegAdded.insert(*Alias))
LRegs.push_back(*Alias);
}
CheckForLiveRegDef(SU, *Reg, LiveRegDefs, RegAdded, LRegs, TRI);
}
}
return !LRegs.empty();

View File

@ -0,0 +1,17 @@
; RUN: llc < %s -march=x86 -mtriple=i686-apple-darwin -pre-RA-sched=fast \
; RUN: | FileCheck %s
; make sure scheduler honors the flags clobber. PR 7882.
define i32 @main(i32 %argc, i8** %argv) nounwind
{
entry:
; CHECK: InlineAsm End
; CHECK: cmpl
%res = icmp slt i32 1, %argc
%tmp = call i32 asm sideeffect alignstack
"push $$0
popf
mov $$13, $0", "=r,r,~{memory},~{flags}" (i1 %res)
%ret = select i1 %res, i32 %tmp, i32 42
ret i32 %ret
}