Skip to content

Commit

Permalink
GlobalISel: support swifterror attribute on AArch64.
Browse files Browse the repository at this point in the history
swifterror marks an argument as a register pretending to be a pointer, so we
need a guaranteed mem2reg-like analysis of its uses. Fortunately most of the
infrastructure can be reused from the DAG world.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@361608 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
TNorthover committed May 24, 2019
1 parent 14ed588 commit 63ef5c0
Show file tree
Hide file tree
Showing 8 changed files with 684 additions and 47 deletions.
56 changes: 48 additions & 8 deletions include/llvm/CodeGen/GlobalISel/CallLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,39 @@ class CallLowering {
CallLowering(const TargetLowering *TLI) : TLI(TLI) {}
virtual ~CallLowering() = default;

/// \return true if the target is capable of handling swifterror values that
/// have been promoted to a specified register. The extended versions of
/// lowerReturn and lowerCall should be implemented.
virtual bool supportSwiftError() const {
return false;
}

/// This hook must be implemented to lower outgoing return values, described
/// by \p Val, into the specified virtual registers \p VRegs.
/// This hook is used by GlobalISel.
///
/// \p SwiftErrorVReg is non-zero if the function has a swifterror parameter
/// that needs to be implicitly returned.
///
/// \return True if the lowering succeeds, false otherwise.
virtual bool lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val,
ArrayRef<unsigned> VRegs,
unsigned SwiftErrorVReg) const {
if (!supportSwiftError()) {
assert(SwiftErrorVReg == 0 && "attempt to use unsupported swifterror");
return lowerReturn(MIRBuilder, Val, VRegs);
}
return false;
}

/// This hook behaves as the extended lowerReturn function, but for targets
/// that do not support swifterror value promotion.
virtual bool lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val,
ArrayRef<unsigned> VRegs) const {
return false;
}


/// This hook must be implemented to lower the incoming (formal)
/// arguments, described by \p Args, for GlobalISel. Each argument
/// must end up in the related virtual register described by VRegs.
Expand All @@ -180,18 +203,29 @@ class CallLowering {
/// \p Callee is the destination of the call. It should be either a register,
/// globaladdress, or externalsymbol.
///
/// \p ResTy is the type returned by the function
/// \p OrigRet is a descriptor for the return type of the function.
///
/// \p ResReg is the generic virtual register that the returned
/// value should be lowered into.
/// \p OrigArgs is a list of descriptors of the arguments passed to the
/// function.
///
/// \p ArgTys is a list of the types each member of \p ArgRegs has; used by
/// the target to decide which register/stack slot should be allocated.
///
/// \p ArgRegs is a list of virtual registers containing each argument that
/// needs to be passed.
/// \p SwiftErrorVReg is non-zero if the call has a swifterror inout
/// parameter, and contains the vreg that the swifterror should be copied into
/// after the call.
///
/// \return true if the lowering succeeded, false otherwise.
virtual bool lowerCall(MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv,
const MachineOperand &Callee, const ArgInfo &OrigRet,
ArrayRef<ArgInfo> OrigArgs,
unsigned SwiftErrorVReg) const {
if (!supportSwiftError()) {
assert(SwiftErrorVReg == 0 && "trying to use unsupported swifterror");
return lowerCall(MIRBuilder, CallConv, Callee, OrigRet, OrigArgs);
}
return false;
}

/// This hook behaves as the extended lowerCall function, but for targets that
/// do not support swifterror value promotion.
virtual bool lowerCall(MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv,
const MachineOperand &Callee, const ArgInfo &OrigRet,
ArrayRef<ArgInfo> OrigArgs) const {
Expand All @@ -209,6 +243,10 @@ class CallLowering {
/// \p ArgRegs is a list of virtual registers containing each argument that
/// needs to be passed.
///
/// \p SwiftErrorVReg is non-zero if the call has a swifterror inout
/// parameter, and contains the vreg that the swifterror should be copied into
/// after the call.
///
/// \p GetCalleeReg is a callback to materialize a register for the callee if
/// the target determines it cannot jump to the destination based purely on \p
/// CI. This might be because \p CI is indirect, or because of the limited
Expand All @@ -217,7 +255,9 @@ class CallLowering {
/// \return true if the lowering succeeded, false otherwise.
bool lowerCall(MachineIRBuilder &MIRBuilder, ImmutableCallSite CS,
unsigned ResReg, ArrayRef<unsigned> ArgRegs,
unsigned SwiftErrorVReg,
std::function<unsigned()> GetCalleeReg) const;

};

} // end namespace llvm
Expand Down
3 changes: 3 additions & 0 deletions include/llvm/CodeGen/GlobalISel/IRTranslator.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/Types.h"
#include "llvm/CodeGen/SwiftErrorValueTracking.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Allocator.h"
Expand Down Expand Up @@ -163,6 +164,8 @@ class IRTranslator : public MachineFunctionPass {
/// this function.
DenseMap<const AllocaInst *, int> FrameIndices;

SwiftErrorValueTracking SwiftError;

/// \name Methods for translating form LLVM IR to MachineInstr.
/// \see ::translate for general information on the translate methods.
/// @{
Expand Down
14 changes: 8 additions & 6 deletions lib/CodeGen/GlobalISel/CallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ using namespace llvm;

void CallLowering::anchor() {}

bool CallLowering::lowerCall(
MachineIRBuilder &MIRBuilder, ImmutableCallSite CS, unsigned ResReg,
ArrayRef<unsigned> ArgRegs, std::function<unsigned()> GetCalleeReg) const {
bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, ImmutableCallSite CS,
unsigned ResReg, ArrayRef<unsigned> ArgRegs,
unsigned SwiftErrorVReg,
std::function<unsigned()> GetCalleeReg) const {
auto &DL = CS.getParent()->getParent()->getParent()->getDataLayout();

// First step is to marshall all the function's parameters into the correct
Expand All @@ -41,8 +42,8 @@ bool CallLowering::lowerCall(
ArgInfo OrigArg{ArgRegs[i], Arg->getType(), ISD::ArgFlagsTy{},
i < NumFixedArgs};
setArgFlags(OrigArg, i + AttributeList::FirstArgIndex, DL, CS);
// We don't currently support swifterror or swiftself args.
if (OrigArg.Flags.isSwiftError() || OrigArg.Flags.isSwiftSelf())
// We don't currently support swiftself args.
if (OrigArg.Flags.isSwiftSelf())
return false;
OrigArgs.push_back(OrigArg);
++i;
Expand All @@ -58,7 +59,8 @@ bool CallLowering::lowerCall(
if (!OrigRet.Ty->isVoidTy())
setArgFlags(OrigRet, AttributeList::ReturnIndex, DL, CS);

return lowerCall(MIRBuilder, CS.getCallingConv(), Callee, OrigRet, OrigArgs);
return lowerCall(MIRBuilder, CS.getCallingConv(), Callee, OrigRet, OrigArgs,
SwiftErrorVReg);
}

template <typename FuncInfoTy>
Expand Down
89 changes: 78 additions & 11 deletions lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,16 @@ bool IRTranslator::translateRet(const User &U, MachineIRBuilder &MIRBuilder) {
if (Ret)
VRegs = getOrCreateVRegs(*Ret);

unsigned SwiftErrorVReg = 0;
if (CLI->supportSwiftError() && SwiftError.getFunctionArg()) {
SwiftErrorVReg = SwiftError.getOrCreateVRegUseAt(
&RI, &MIRBuilder.getMBB(), SwiftError.getFunctionArg());
}

// The target may mess up with the insertion point, but
// this is not important as a return is the last instruction
// of the block anyway.

return CLI->lowerReturn(MIRBuilder, Ret, VRegs);
return CLI->lowerReturn(MIRBuilder, Ret, VRegs, SwiftErrorVReg);
}

bool IRTranslator::translateBr(const User &U, MachineIRBuilder &MIRBuilder) {
Expand Down Expand Up @@ -447,6 +452,14 @@ bool IRTranslator::translateIndirectBr(const User &U,
return true;
}

static bool isSwiftError(const Value *V) {
if (auto Arg = dyn_cast<Argument>(V))
return Arg->hasSwiftErrorAttr();
if (auto AI = dyn_cast<AllocaInst>(V))
return AI->isSwiftError();
return false;
}

bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) {
const LoadInst &LI = cast<LoadInst>(U);

Expand All @@ -464,6 +477,15 @@ bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) {
Type *OffsetIRTy = DL->getIntPtrType(LI.getPointerOperandType());
LLT OffsetTy = getLLTForType(*OffsetIRTy, *DL);

if (CLI->supportSwiftError() && isSwiftError(LI.getPointerOperand())) {
assert(Regs.size() == 1 && "swifterror should be single pointer");
unsigned VReg = SwiftError.getOrCreateVRegUseAt(&LI, &MIRBuilder.getMBB(),
LI.getPointerOperand());
MIRBuilder.buildCopy(Regs[0], VReg);
return true;
}


for (unsigned i = 0; i < Regs.size(); ++i) {
unsigned Addr = 0;
MIRBuilder.materializeGEP(Addr, Base, OffsetTy, Offsets[i] / 8);
Expand Down Expand Up @@ -496,6 +518,15 @@ bool IRTranslator::translateStore(const User &U, MachineIRBuilder &MIRBuilder) {
Type *OffsetIRTy = DL->getIntPtrType(SI.getPointerOperandType());
LLT OffsetTy = getLLTForType(*OffsetIRTy, *DL);

if (CLI->supportSwiftError() && isSwiftError(SI.getPointerOperand())) {
assert(Vals.size() == 1 && "swifterror should be single pointer");

unsigned VReg = SwiftError.getOrCreateVRegDefAt(&SI, &MIRBuilder.getMBB(),
SI.getPointerOperand());
MIRBuilder.buildCopy(VReg, Vals[0]);
return true;
}

for (unsigned i = 0; i < Vals.size(); ++i) {
unsigned Addr = 0;
MIRBuilder.materializeGEP(Addr, Base, OffsetTy, Offsets[i] / 8);
Expand Down Expand Up @@ -1154,16 +1185,29 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
: getOrCreateVReg(CI);

SmallVector<unsigned, 8> Args;
for (auto &Arg: CI.arg_operands())
unsigned SwiftErrorVReg = 0;
for (auto &Arg: CI.arg_operands()) {
if (CLI->supportSwiftError() && isSwiftError(Arg)) {
LLT Ty = getLLTForType(*Arg->getType(), *DL);
unsigned InVReg = MRI->createGenericVirtualRegister(Ty);
MIRBuilder.buildCopy(InVReg, SwiftError.getOrCreateVRegUseAt(
&CI, &MIRBuilder.getMBB(), Arg));
Args.push_back(InVReg);
SwiftErrorVReg =
SwiftError.getOrCreateVRegDefAt(&CI, &MIRBuilder.getMBB(), Arg);
continue;
}
Args.push_back(packRegs(*Arg, MIRBuilder));
}

MF->getFrameInfo().setHasCalls(true);
bool Success = CLI->lowerCall(MIRBuilder, &CI, Res, Args, [&]() {
return getOrCreateVReg(*CI.getCalledValue());
});
bool Success =
CLI->lowerCall(MIRBuilder, &CI, Res, Args, SwiftErrorVReg,
[&]() { return getOrCreateVReg(*CI.getCalledValue()); });

if (IsSplitType)
unpackRegs(CI, Res, MIRBuilder);

return Success;
}

Expand Down Expand Up @@ -1239,10 +1283,23 @@ bool IRTranslator::translateInvoke(const User &U,
if (!I.getType()->isVoidTy())
Res = MRI->createGenericVirtualRegister(getLLTForType(*I.getType(), *DL));
SmallVector<unsigned, 8> Args;
for (auto &Arg: I.arg_operands())
unsigned SwiftErrorVReg = 0;
for (auto &Arg : I.arg_operands()) {
if (CLI->supportSwiftError() && isSwiftError(Arg)) {
LLT Ty = getLLTForType(*Arg->getType(), *DL);
unsigned InVReg = MRI->createGenericVirtualRegister(Ty);
MIRBuilder.buildCopy(InVReg, SwiftError.getOrCreateVRegUseAt(
&I, &MIRBuilder.getMBB(), Arg));
Args.push_back(InVReg);
SwiftErrorVReg =
SwiftError.getOrCreateVRegDefAt(&I, &MIRBuilder.getMBB(), Arg);
continue;
}

Args.push_back(packRegs(*Arg, MIRBuilder));
}

if (!CLI->lowerCall(MIRBuilder, &I, Res, Args,
if (!CLI->lowerCall(MIRBuilder, &I, Res, Args, SwiftErrorVReg,
[&]() { return getOrCreateVReg(*I.getCalledValue()); }))
return false;

Expand Down Expand Up @@ -1331,7 +1388,7 @@ bool IRTranslator::translateAlloca(const User &U,
auto &AI = cast<AllocaInst>(U);

if (AI.isSwiftError())
return false;
return true;

if (AI.isStaticAlloca()) {
unsigned Res = getOrCreateVReg(AI);
Expand Down Expand Up @@ -1776,6 +1833,10 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
MF->push_back(EntryBB);
EntryBuilder->setMBB(*EntryBB);

DebugLoc DbgLoc = F.getEntryBlock().getFirstNonPHI()->getDebugLoc();
SwiftError.setFunction(CurMF);
SwiftError.createEntriesInEntryBlock(DbgLoc);

// Create all blocks, in IR order, to preserve the layout.
for (const BasicBlock &BB: F) {
auto *&MBB = BBToMBB[&BB];
Expand All @@ -1797,14 +1858,18 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
continue; // Don't handle zero sized types.
VRegArgs.push_back(
MRI->createGenericVirtualRegister(getLLTForType(*Arg.getType(), *DL)));

if (Arg.hasSwiftErrorAttr())
SwiftError.setCurrentVReg(EntryBB, SwiftError.getFunctionArg(),
VRegArgs.back());
}

// We don't currently support translating swifterror or swiftself functions.
for (auto &Arg : F.args()) {
if (Arg.hasSwiftErrorAttr() || Arg.hasSwiftSelfAttr()) {
if (Arg.hasSwiftSelfAttr()) {
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
F.getSubprogram(), &F.getEntryBlock());
R << "unable to lower arguments due to swifterror/swiftself: "
R << "unable to lower arguments due to swiftself: "
<< ore::NV("Prototype", F.getType());
reportTranslationError(*MF, *TPC, *ORE, R);
return false;
Expand Down Expand Up @@ -1880,6 +1945,8 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {

finishPendingPhis();

SwiftError.propagateVRegs();

// Merge the argument lowering and constants block with its single
// successor, the LLVM-IR entry block. We want the basic block to
// be maximal.
Expand Down
16 changes: 14 additions & 2 deletions lib/Target/AArch64/AArch64CallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ void AArch64CallLowering::splitToValueTypes(

bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
const Value *Val,
ArrayRef<unsigned> VRegs) const {
ArrayRef<unsigned> VRegs,
unsigned SwiftErrorVReg) const {
auto MIB = MIRBuilder.buildInstrNoInsert(AArch64::RET_ReallyLR);
assert(((Val && !VRegs.empty()) || (!Val && VRegs.empty())) &&
"Return value without a vreg");
Expand Down Expand Up @@ -340,6 +341,11 @@ bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
Success = handleAssignments(MIRBuilder, SplitArgs, Handler);
}

if (SwiftErrorVReg) {
MIB.addUse(AArch64::X21, RegState::Implicit);
MIRBuilder.buildCopy(AArch64::X21, SwiftErrorVReg);
}

MIRBuilder.insertInstr(MIB);
return Success;
}
Expand Down Expand Up @@ -420,7 +426,8 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
CallingConv::ID CallConv,
const MachineOperand &Callee,
const ArgInfo &OrigRet,
ArrayRef<ArgInfo> OrigArgs) const {
ArrayRef<ArgInfo> OrigArgs,
unsigned SwiftErrorVReg) const {
MachineFunction &MF = MIRBuilder.getMF();
const Function &F = MF.getFunction();
MachineRegisterInfo &MRI = MF.getRegInfo();
Expand Down Expand Up @@ -503,6 +510,11 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
MIRBuilder.buildSequence(OrigRet.Reg, SplitRegs, RegOffsets);
}

if (SwiftErrorVReg) {
MIB.addDef(AArch64::X21, RegState::Implicit);
MIRBuilder.buildCopy(SwiftErrorVReg, AArch64::X21);
}

CallSeqStart.addImm(Handler.StackSize).addImm(0);
MIRBuilder.buildInstr(AArch64::ADJCALLSTACKUP)
.addImm(Handler.StackSize)
Expand Down
14 changes: 12 additions & 2 deletions lib/Target/AArch64/AArch64CallLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,24 @@ class AArch64CallLowering: public CallLowering {
AArch64CallLowering(const AArch64TargetLowering &TLI);

bool lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val,
ArrayRef<unsigned> VRegs) const override;
ArrayRef<unsigned> VRegs,
unsigned SwiftErrorVReg) const override;

bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F,
ArrayRef<unsigned> VRegs) const override;

bool lowerCall(MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv,
const MachineOperand &Callee, const ArgInfo &OrigRet,
ArrayRef<ArgInfo> OrigArgs) const override;
ArrayRef<ArgInfo> OrigArgs,
unsigned SwiftErrorVReg) const override;

bool lowerCall(MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv,
const MachineOperand &Callee, const ArgInfo &OrigRet,
ArrayRef<ArgInfo> OrigArgs) const override {
return lowerCall(MIRBuilder, CallConv, Callee, OrigRet, OrigArgs, 0);
}

bool supportSwiftError() const override { return true; }

private:
using RegHandler = std::function<void(MachineIRBuilder &, Type *, unsigned,
Expand Down
Loading

0 comments on commit 63ef5c0

Please sign in to comment.