1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

ISel: Fix FastISel of swifterror values

The code assumed that we process instructions in basic block order.  FastISel
processes instructions in reverse basic block order. We need to pre-assign
virtual registers before selecting otherwise we get def-use relationships wrong.

This only affects code with swifterror registers.

rdar://32659327

llvm-svn: 305484
This commit is contained in:
Arnold Schwaighofer 2017-06-15 17:34:42 +00:00
parent 6feaee6e84
commit c86f47bee2
7 changed files with 300 additions and 14 deletions

View File

@ -82,6 +82,11 @@ public:
DenseMap<std::pair<const MachineBasicBlock *, const Value *>, unsigned>
SwiftErrorVRegUpwardsUse;
/// A map from instructions that define/use a swifterror value to the virtual
/// register that represents that def/use.
llvm::DenseMap<PointerIntPair<const Instruction *, 1, bool>, unsigned>
SwiftErrorVRegDefUses;
/// The swifterror argument of the current function.
const Value *SwiftErrorArg;
@ -101,6 +106,13 @@ public:
void setCurrentSwiftErrorVReg(const MachineBasicBlock *MBB, const Value *,
unsigned);
/// Get or create the swifterror value virtual register for a def of a
/// swifterror by an instruction.
std::pair<unsigned, bool> getOrCreateSwiftErrorVRegDefAt(const Instruction *);
std::pair<unsigned, bool>
getOrCreateSwiftErrorVRegUseAt(const Instruction *, const MachineBasicBlock *,
const Value *);
/// ValueMap - Since we emit code for the function a basic block at a time,
/// we must remember which virtual registers hold the values for
/// cross-basic-block values.

View File

@ -523,3 +523,29 @@ void FunctionLoweringInfo::setCurrentSwiftErrorVReg(
const MachineBasicBlock *MBB, const Value *Val, unsigned VReg) {
SwiftErrorVRegDefMap[std::make_pair(MBB, Val)] = VReg;
}
std::pair<unsigned, bool>
FunctionLoweringInfo::getOrCreateSwiftErrorVRegDefAt(const Instruction *I) {
auto Key = PointerIntPair<const Instruction *, 1, bool>(I, true);
auto It = SwiftErrorVRegDefUses.find(Key);
if (It == SwiftErrorVRegDefUses.end()) {
auto &DL = MF->getDataLayout();
const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
unsigned VReg = MF->getRegInfo().createVirtualRegister(RC);
SwiftErrorVRegDefUses[Key] = VReg;
return std::make_pair(VReg, true);
}
return std::make_pair(It->second, false);
}
std::pair<unsigned, bool>
FunctionLoweringInfo::getOrCreateSwiftErrorVRegUseAt(const Instruction *I, const MachineBasicBlock *MBB, const Value *Val) {
auto Key = PointerIntPair<const Instruction *, 1, bool>(I, false);
auto It = SwiftErrorVRegDefUses.find(Key);
if (It == SwiftErrorVRegDefUses.end()) {
unsigned VReg = getOrCreateSwiftErrorVReg(MBB, Val);
SwiftErrorVRegDefUses[Key] = VReg;
return std::make_pair(VReg, true);
}
return std::make_pair(It->second, false);
}

View File

@ -1496,9 +1496,10 @@ void SelectionDAGBuilder::visitRet(const ReturnInst &I) {
true /*isfixed*/, 1 /*origidx*/,
0 /*partOffs*/));
// Create SDNode for the swifterror virtual register.
OutVals.push_back(DAG.getRegister(FuncInfo.getOrCreateSwiftErrorVReg(
FuncInfo.MBB, FuncInfo.SwiftErrorArg),
EVT(TLI.getPointerTy(DL))));
OutVals.push_back(
DAG.getRegister(FuncInfo.getOrCreateSwiftErrorVRegUseAt(
&I, FuncInfo.MBB, FuncInfo.SwiftErrorArg).first,
EVT(TLI.getPointerTy(DL))));
}
bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg();
@ -3595,15 +3596,15 @@ void SelectionDAGBuilder::visitStoreToSwiftError(const StoreInst &I) {
SDValue Src = getValue(SrcV);
// Create a virtual register, then update the virtual register.
auto &DL = DAG.getDataLayout();
const TargetRegisterClass *RC = TLI.getRegClassFor(TLI.getPointerTy(DL));
unsigned VReg = FuncInfo.MF->getRegInfo().createVirtualRegister(RC);
unsigned VReg; bool CreatedVReg;
std::tie(VReg, CreatedVReg) = FuncInfo.getOrCreateSwiftErrorVRegDefAt(&I);
// Chain, DL, Reg, N or Chain, DL, Reg, N, Glue
// Chain can be getRoot or getControlRoot.
SDValue CopyNode = DAG.getCopyToReg(getRoot(), getCurSDLoc(), VReg,
SDValue(Src.getNode(), Src.getResNo()));
DAG.setRoot(CopyNode);
FuncInfo.setCurrentSwiftErrorVReg(FuncInfo.MBB, I.getOperand(1), VReg);
if (CreatedVReg)
FuncInfo.setCurrentSwiftErrorVReg(FuncInfo.MBB, I.getOperand(1), VReg);
}
void SelectionDAGBuilder::visitLoadFromSwiftError(const LoadInst &I) {
@ -3633,7 +3634,8 @@ void SelectionDAGBuilder::visitLoadFromSwiftError(const LoadInst &I) {
// Chain, DL, Reg, VT, Glue or Chain, DL, Reg, VT
SDValue L = DAG.getCopyFromReg(
getRoot(), getCurSDLoc(),
FuncInfo.getOrCreateSwiftErrorVReg(FuncInfo.MBB, SV), ValueVTs[0]);
FuncInfo.getOrCreateSwiftErrorVRegUseAt(&I, FuncInfo.MBB, SV).first,
ValueVTs[0]);
setValue(&I, L);
}
@ -6030,9 +6032,11 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee,
SwiftErrorVal = V;
// We find the virtual register for the actual swifterror argument.
// Instead of using the Value, we use the virtual register instead.
Entry.Node =
DAG.getRegister(FuncInfo.getOrCreateSwiftErrorVReg(FuncInfo.MBB, V),
EVT(TLI.getPointerTy(DL)));
Entry.Node = DAG.getRegister(FuncInfo
.getOrCreateSwiftErrorVRegUseAt(
CS.getInstruction(), FuncInfo.MBB, V)
.first,
EVT(TLI.getPointerTy(DL)));
}
Args.push_back(Entry);
@ -6073,11 +6077,13 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee,
if (SwiftErrorVal && TLI.supportSwiftError()) {
// Get the last element of InVals.
SDValue Src = CLI.InVals.back();
const TargetRegisterClass *RC = TLI.getRegClassFor(TLI.getPointerTy(DL));
unsigned VReg = FuncInfo.MF->getRegInfo().createVirtualRegister(RC);
unsigned VReg; bool CreatedVReg;
std::tie(VReg, CreatedVReg) =
FuncInfo.getOrCreateSwiftErrorVRegDefAt(CS.getInstruction());
SDValue CopyNode = CLI.DAG.getCopyToReg(Result.second, CLI.DL, VReg, Src);
// We update the virtual register for the actual swifterror argument.
FuncInfo.setCurrentSwiftErrorVReg(FuncInfo.MBB, SwiftErrorVal, VReg);
if (CreatedVReg)
FuncInfo.setCurrentSwiftErrorVReg(FuncInfo.MBB, SwiftErrorVal, VReg);
DAG.setRoot(CopyNode);
}
}

View File

@ -1055,6 +1055,7 @@ static void setupSwiftErrorVals(const Function &Fn, const TargetLowering *TLI,
FuncInfo->SwiftErrorVals.clear();
FuncInfo->SwiftErrorVRegDefMap.clear();
FuncInfo->SwiftErrorVRegUpwardsUse.clear();
FuncInfo->SwiftErrorVRegDefUses.clear();
FuncInfo->SwiftErrorArg = nullptr;
// Check if function has a swifterror argument.
@ -1278,6 +1279,80 @@ static void propagateSwiftErrorVRegs(FunctionLoweringInfo *FuncInfo) {
}
}
void preassignSwiftErrorRegs(const TargetLowering *TLI,
FunctionLoweringInfo *FuncInfo,
BasicBlock::const_iterator Begin,
BasicBlock::const_iterator End) {
if (!TLI->supportSwiftError() || FuncInfo->SwiftErrorVals.empty())
return;
// Iterator over instructions and assign vregs to swifterror defs and uses.
for (auto It = Begin; It != End; ++It) {
ImmutableCallSite CS(&*It);
if (CS) {
// A call-site with a swifterror argument is both use and def.
const Value *SwiftErrorAddr = nullptr;
for (auto &Arg : CS.args()) {
if (!Arg->isSwiftError())
continue;
// Use of swifterror.
assert(!SwiftErrorAddr && "Cannot have multiple swifterror arguments");
SwiftErrorAddr = &*Arg;
assert(SwiftErrorAddr->isSwiftError() &&
"Must have a swifterror value argument");
unsigned VReg; bool CreatedReg;
std::tie(VReg, CreatedReg) = FuncInfo->getOrCreateSwiftErrorVRegUseAt(
&*It, FuncInfo->MBB, SwiftErrorAddr);
assert(CreatedReg);
}
if (!SwiftErrorAddr)
continue;
// Def of swifterror.
unsigned VReg; bool CreatedReg;
std::tie(VReg, CreatedReg) =
FuncInfo->getOrCreateSwiftErrorVRegDefAt(&*It);
assert(CreatedReg);
FuncInfo->setCurrentSwiftErrorVReg(FuncInfo->MBB, SwiftErrorAddr, VReg);
// A load is a use.
} else if (const LoadInst *LI = dyn_cast<const LoadInst>(&*It)) {
const Value *V = LI->getOperand(0);
if (!V->isSwiftError())
continue;
unsigned VReg; bool CreatedReg;
std::tie(VReg, CreatedReg) =
FuncInfo->getOrCreateSwiftErrorVRegUseAt(LI, FuncInfo->MBB, V);
assert(CreatedReg);
// A store is a def.
} else if (const StoreInst *SI = dyn_cast<const StoreInst>(&*It)) {
const Value *SwiftErrorAddr = SI->getOperand(1);
if (!SwiftErrorAddr->isSwiftError())
continue;
// Def of swifterror.
unsigned VReg; bool CreatedReg;
std::tie(VReg, CreatedReg) =
FuncInfo->getOrCreateSwiftErrorVRegDefAt(&*It);
assert(CreatedReg);
FuncInfo->setCurrentSwiftErrorVReg(FuncInfo->MBB, SwiftErrorAddr, VReg);
// A return in a swiferror returning function is a use.
} else if (const ReturnInst *R = dyn_cast<const ReturnInst>(&*It)) {
const Function *F = R->getParent()->getParent();
if(!F->getAttributes().hasAttrSomewhere(Attribute::SwiftError))
continue;
unsigned VReg; bool CreatedReg;
std::tie(VReg, CreatedReg) = FuncInfo->getOrCreateSwiftErrorVRegUseAt(
R, FuncInfo->MBB, FuncInfo->SwiftErrorArg);
assert(CreatedReg);
}
}
}
void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
FastISelFailed = false;
// Initialize the Fast-ISel state, if needed.
@ -1384,6 +1459,10 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
FastIS->startNewBlock();
unsigned NumFastIselRemaining = std::distance(Begin, End);
// Pre-assign swifterror vregs.
preassignSwiftErrorRegs(TLI, FuncInfo, Begin, End);
// Do FastISel on as many instructions as possible.
for (; BI != Begin; --BI) {
const Instruction *Inst = &*std::prev(BI);

View File

@ -597,3 +597,30 @@ entry:
tail call void @acallee(i8* null)
ret void
}
declare swiftcc void @foo2(%swift_error** swifterror)
; Make sure we properly assign registers during fast-isel.
; CHECK-O0-LABEL: testAssign
; CHECK-O0: mov [[TMP:x.*]], xzr
; CHECK-O0: mov x21, [[TMP]]
; CHECK-O0: bl _foo2
; CHECK-O0: str x21, [s[[STK:.*]]]
; CHECK-O0: ldr x0, [s[[STK]]]
; CHECK-APPLE-LABEL: testAssign
; CHECK-APPLE: mov x21, xzr
; CHECK-APPLE: bl _foo2
; CHECK-APPLE: mov x0, x21
define swiftcc %swift_error* @testAssign(i8* %error_ref) {
entry:
%error_ptr = alloca swifterror %swift_error*
store %swift_error* null, %swift_error** %error_ptr
call swiftcc void @foo2(%swift_error** swifterror %error_ptr)
br label %a
a:
%error = load %swift_error*, %swift_error** %error_ptr
ret %swift_error* %error
}

View File

@ -528,3 +528,31 @@ entry:
tail call void @acallee(i8* null)
ret void
}
declare swiftcc void @foo2(%swift_error** swifterror)
; Make sure we properly assign registers during fast-isel.
; CHECK-O0-LABEL: testAssign
; CHECK-O0: mov r8, #0
; CHECK-O0: bl _foo2
; CHECK-O0: str r8, [s[[STK:p.*]]]
; CHECK-O0: ldr r0, [s[[STK]]]
; CHECK-O0: pop
; CHECK-APPLE-LABEL: testAssign
; CHECK-APPLE: mov r8, #0
; CHECK-APPLE: bl _foo2
; CHECK-APPLE: mov r0, r8
define swiftcc %swift_error* @testAssign(i8* %error_ref) {
entry:
%error_ptr = alloca swifterror %swift_error*
store %swift_error* null, %swift_error** %error_ptr
call swiftcc void @foo2(%swift_error** swifterror %error_ptr)
br label %a
a:
%error = load %swift_error*, %swift_error** %error_ptr
ret %swift_error* %error
}

View File

@ -712,3 +712,111 @@ trueBB:
falseBB:
ret void
}
declare swiftcc void @foo2(%swift_error** swifterror)
; Make sure we properly assign registers during fast-isel.
; CHECK-O0-LABEL: testAssign
; CHECK-O0: pushq %r12
; CHECK-O0: xorl [[ZERO:%[a-z0-9]+]], [[ZERO]]
; CHECK-O0: movl [[ZERO]], %r12d
; CHECK-O0: callq _foo2
; CHECK-O0: movq %r12, [[SLOT:[-a-z0-9\(\)\%]*]]
;
; CHECK-O0: movq [[SLOT]], %rax
; CHECK-O0: popq %r12
; CHECK-O0: retq
; CHECK-APPLE-LABEL: testAssign
; CHECK-APPLE: pushq %r12
; CHECK-APPLE: xorl %r12d, %r12d
; CHECK-APPLE: callq _foo2
; CHECK-APPLE: movq %r12, %rax
; CHECK-APPLE: popq %r12
; CHECK-APPLE: retq
define swiftcc %swift_error* @testAssign(i8* %error_ref) {
entry:
%error_ptr = alloca swifterror %swift_error*
store %swift_error* null, %swift_error** %error_ptr
call swiftcc void @foo2(%swift_error** swifterror %error_ptr)
br label %a
a:
%error = load %swift_error*, %swift_error** %error_ptr
ret %swift_error* %error
}
; CHECK-O0-LABEL: testAssign2
; CHECK-O0: movq %r12, {{.*}}
; CHECK-O0: movq %r12, [[SLOT:[-a-z0-9\(\)\%]*]]
; CHECK-O0: jmp
; CHECK-O0: movq [[SLOT]], %rax
; CHECK-O0: movq %rax, [[SLOT2:[-a-z0-9\(\)\%]*]]
; CHECK-O0: movq [[SLOT2]], %r12
; CHECK-O0: retq
; CHECK-APPLE-LABEL: testAssign2
; CHECK-APPLE: movq %r12, %rax
; CHECK-APPLE: retq
define swiftcc %swift_error* @testAssign2(i8* %error_ref, %swift_error** swifterror %err) {
entry:
br label %a
a:
%error = load %swift_error*, %swift_error** %err
ret %swift_error* %error
}
; CHECK-O0-LABEL: testAssign3
; CHECK-O0: callq _foo2
; CHECK-O0: movq %r12, [[SLOT:[-a-z0-9\(\)\%]*]]
; CHECK-O0: movq [[SLOT]], %rax
; CHECK-O0: movq %rax, [[SLOT2:[-a-z0-9\(\)\%]*]]
; CHECK-O0: movq [[SLOT2]], %r12
; CHECK-O0: addq $24, %rsp
; CHECK-O0: retq
; CHECK-APPLE-LABEL: testAssign3
; CHECK-APPLE: callq _foo2
; CHECK-APPLE: movq %r12, %rax
; CHECK-APPLE: retq
define swiftcc %swift_error* @testAssign3(i8* %error_ref, %swift_error** swifterror %err) {
entry:
call swiftcc void @foo2(%swift_error** swifterror %err)
br label %a
a:
%error = load %swift_error*, %swift_error** %err
ret %swift_error* %error
}
; CHECK-O0-LABEL: testAssign4
; CHECK-O0: callq _foo2
; CHECK-O0: xorl %ecx, %ecx
; CHECK-O0: movl %ecx, %eax
; CHECK-O0: movq %rax, [[SLOT:[-a-z0-9\(\)\%]*]]
; CHECK-O0: movq [[SLOT]], %rax
; CHECK-O0: movq %rax, [[SLOT2:[-a-z0-9\(\)\%]*]]
; CHECK-O0: movq [[SLOT2]], %r12
; CHECK-O0: retq
; CHECK-APPLE-LABEL: testAssign4
; CHECK-APPLE: callq _foo2
; CHECK-APPLE: xorl %eax, %eax
; CHECK-APPLE: xorl %r12d, %r12d
; CHECK-APPLE: retq
define swiftcc %swift_error* @testAssign4(i8* %error_ref, %swift_error** swifterror %err) {
entry:
call swiftcc void @foo2(%swift_error** swifterror %err)
store %swift_error* null, %swift_error** %err
br label %a
a:
%error = load %swift_error*, %swift_error** %err
ret %swift_error* %error
}