2016-08-30 03:07:08 +08:00
|
|
|
//===-- lib/CodeGen/GlobalISel/CallLowering.cpp - Call lowering -----------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
///
|
|
|
|
/// \file
|
|
|
|
/// This file implements some simple delegations needed for call lowering.
|
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
|
2016-12-05 18:40:33 +08:00
|
|
|
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
2016-08-30 03:07:08 +08:00
|
|
|
#include "llvm/CodeGen/MachineOperand.h"
|
2016-12-13 18:46:12 +08:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2016-09-21 20:57:45 +08:00
|
|
|
#include "llvm/IR/DataLayout.h"
|
2016-12-05 18:40:33 +08:00
|
|
|
#include "llvm/IR/Instructions.h"
|
2016-09-21 20:57:45 +08:00
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/Target/TargetLowering.h"
|
2016-08-30 03:07:08 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
bool CallLowering::lowerCall(
|
2017-03-10 08:25:44 +08:00
|
|
|
MachineIRBuilder &MIRBuilder, ImmutableCallSite CS, unsigned ResReg,
|
2016-08-30 03:07:08 +08:00
|
|
|
ArrayRef<unsigned> ArgRegs, std::function<unsigned()> GetCalleeReg) const {
|
2017-03-10 08:25:44 +08:00
|
|
|
auto &DL = CS.getParent()->getParent()->getParent()->getDataLayout();
|
2016-09-21 20:57:45 +08:00
|
|
|
|
2016-08-30 03:07:08 +08:00
|
|
|
// First step is to marshall all the function's parameters into the correct
|
|
|
|
// physregs and memory locations. Gather the sequence of argument types that
|
|
|
|
// we'll pass to the assigner function.
|
2016-09-21 20:57:45 +08:00
|
|
|
SmallVector<ArgInfo, 8> OrigArgs;
|
|
|
|
unsigned i = 0;
|
2017-03-10 08:25:44 +08:00
|
|
|
unsigned NumFixedArgs = CS.getFunctionType()->getNumParams();
|
|
|
|
for (auto &Arg : CS.args()) {
|
2017-01-18 06:30:10 +08:00
|
|
|
ArgInfo OrigArg{ArgRegs[i], Arg->getType(), ISD::ArgFlagsTy{},
|
|
|
|
i < NumFixedArgs};
|
2017-05-04 02:17:31 +08:00
|
|
|
setArgFlags(OrigArg, i + AttributeList::FirstArgIndex, DL, CS);
|
2016-09-21 20:57:45 +08:00
|
|
|
OrigArgs.push_back(OrigArg);
|
|
|
|
++i;
|
|
|
|
}
|
2016-08-30 03:07:08 +08:00
|
|
|
|
|
|
|
MachineOperand Callee = MachineOperand::CreateImm(0);
|
2017-03-10 08:25:44 +08:00
|
|
|
if (const Function *F = CS.getCalledFunction())
|
2016-08-30 03:07:08 +08:00
|
|
|
Callee = MachineOperand::CreateGA(F, 0);
|
|
|
|
else
|
|
|
|
Callee = MachineOperand::CreateReg(GetCalleeReg(), false);
|
|
|
|
|
2017-03-10 08:25:44 +08:00
|
|
|
ArgInfo OrigRet{ResReg, CS.getType(), ISD::ArgFlagsTy{}};
|
2016-09-21 20:57:45 +08:00
|
|
|
if (!OrigRet.Ty->isVoidTy())
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-22 00:57:19 +08:00
|
|
|
setArgFlags(OrigRet, AttributeList::ReturnIndex, DL, CS);
|
2016-09-21 20:57:45 +08:00
|
|
|
|
2017-03-20 22:40:18 +08:00
|
|
|
return lowerCall(MIRBuilder, CS.getCallingConv(), Callee, OrigRet, OrigArgs);
|
2016-08-30 03:07:08 +08:00
|
|
|
}
|
2016-09-21 20:57:45 +08:00
|
|
|
|
|
|
|
template <typename FuncInfoTy>
|
|
|
|
void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg, unsigned OpIdx,
|
|
|
|
const DataLayout &DL,
|
|
|
|
const FuncInfoTy &FuncInfo) const {
|
Rename AttributeSet to AttributeList
Summary:
This class is a list of AttributeSetNodes corresponding the function
prototype of a call or function declaration. This class used to be
called ParamAttrListPtr, then AttrListPtr, then AttributeSet. It is
typically accessed by parameter and return value index, so
"AttributeList" seems like a more intuitive name.
Rename AttributeSetImpl to AttributeListImpl to follow suit.
It's useful to rename this class so that we can rename AttributeSetNode
to AttributeSet later. AttributeSet is the set of attributes that apply
to a single function, argument, or return value.
Reviewers: sanjoy, javed.absar, chandlerc, pete
Reviewed By: pete
Subscribers: pete, jholewinski, arsenm, dschuff, mehdi_amini, jfb, nhaehnle, sbc100, void, llvm-commits
Differential Revision: https://reviews.llvm.org/D31102
llvm-svn: 298393
2017-03-22 00:57:19 +08:00
|
|
|
const AttributeList &Attrs = FuncInfo.getAttributes();
|
2016-09-21 20:57:45 +08:00
|
|
|
if (Attrs.hasAttribute(OpIdx, Attribute::ZExt))
|
|
|
|
Arg.Flags.setZExt();
|
|
|
|
if (Attrs.hasAttribute(OpIdx, Attribute::SExt))
|
|
|
|
Arg.Flags.setSExt();
|
|
|
|
if (Attrs.hasAttribute(OpIdx, Attribute::InReg))
|
|
|
|
Arg.Flags.setInReg();
|
|
|
|
if (Attrs.hasAttribute(OpIdx, Attribute::StructRet))
|
|
|
|
Arg.Flags.setSRet();
|
|
|
|
if (Attrs.hasAttribute(OpIdx, Attribute::SwiftSelf))
|
|
|
|
Arg.Flags.setSwiftSelf();
|
|
|
|
if (Attrs.hasAttribute(OpIdx, Attribute::SwiftError))
|
|
|
|
Arg.Flags.setSwiftError();
|
|
|
|
if (Attrs.hasAttribute(OpIdx, Attribute::ByVal))
|
|
|
|
Arg.Flags.setByVal();
|
|
|
|
if (Attrs.hasAttribute(OpIdx, Attribute::InAlloca))
|
|
|
|
Arg.Flags.setInAlloca();
|
|
|
|
|
|
|
|
if (Arg.Flags.isByVal() || Arg.Flags.isInAlloca()) {
|
|
|
|
Type *ElementTy = cast<PointerType>(Arg.Ty)->getElementType();
|
|
|
|
Arg.Flags.setByValSize(DL.getTypeAllocSize(ElementTy));
|
|
|
|
// For ByVal, alignment should be passed from FE. BE will guess if
|
|
|
|
// this info is not there but there are cases it cannot get right.
|
|
|
|
unsigned FrameAlign;
|
2017-05-03 06:07:37 +08:00
|
|
|
if (FuncInfo.getParamAlignment(OpIdx - 2))
|
|
|
|
FrameAlign = FuncInfo.getParamAlignment(OpIdx - 2);
|
2016-09-21 20:57:45 +08:00
|
|
|
else
|
|
|
|
FrameAlign = getTLI()->getByValTypeAlignment(ElementTy, DL);
|
|
|
|
Arg.Flags.setByValAlign(FrameAlign);
|
|
|
|
}
|
|
|
|
if (Attrs.hasAttribute(OpIdx, Attribute::Nest))
|
|
|
|
Arg.Flags.setNest();
|
|
|
|
Arg.Flags.setOrigAlign(DL.getABITypeAlignment(Arg.Ty));
|
|
|
|
}
|
|
|
|
|
|
|
|
template void
|
|
|
|
CallLowering::setArgFlags<Function>(CallLowering::ArgInfo &Arg, unsigned OpIdx,
|
|
|
|
const DataLayout &DL,
|
|
|
|
const Function &FuncInfo) const;
|
|
|
|
|
|
|
|
template void
|
|
|
|
CallLowering::setArgFlags<CallInst>(CallLowering::ArgInfo &Arg, unsigned OpIdx,
|
|
|
|
const DataLayout &DL,
|
|
|
|
const CallInst &FuncInfo) const;
|
2016-12-05 18:40:33 +08:00
|
|
|
|
|
|
|
bool CallLowering::handleAssignments(MachineIRBuilder &MIRBuilder,
|
|
|
|
ArrayRef<ArgInfo> Args,
|
|
|
|
ValueHandler &Handler) const {
|
|
|
|
MachineFunction &MF = MIRBuilder.getMF();
|
|
|
|
const Function &F = *MF.getFunction();
|
2016-12-06 06:20:32 +08:00
|
|
|
const DataLayout &DL = F.getParent()->getDataLayout();
|
2016-12-05 18:40:33 +08:00
|
|
|
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
|
|
|
CCState CCInfo(F.getCallingConv(), F.isVarArg(), MF, ArgLocs, F.getContext());
|
|
|
|
|
|
|
|
unsigned NumArgs = Args.size();
|
|
|
|
for (unsigned i = 0; i != NumArgs; ++i) {
|
|
|
|
MVT CurVT = MVT::getVT(Args[i].Ty);
|
2017-01-18 06:30:10 +08:00
|
|
|
if (Handler.assignArg(i, CurVT, CurVT, CCValAssign::Full, Args[i], CCInfo))
|
2016-12-05 18:40:33 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-02-16 15:53:07 +08:00
|
|
|
for (unsigned i = 0, e = Args.size(), j = 0; i != e; ++i, ++j) {
|
|
|
|
assert(j < ArgLocs.size() && "Skipped too many arg locs");
|
|
|
|
|
|
|
|
CCValAssign &VA = ArgLocs[j];
|
|
|
|
assert(VA.getValNo() == i && "Location doesn't correspond to current arg");
|
|
|
|
|
|
|
|
if (VA.needsCustom()) {
|
|
|
|
j += Handler.assignCustomValue(Args[i], makeArrayRef(ArgLocs).slice(j));
|
|
|
|
continue;
|
|
|
|
}
|
2016-12-05 18:40:33 +08:00
|
|
|
|
|
|
|
if (VA.isRegLoc())
|
|
|
|
Handler.assignValueToReg(Args[i].Reg, VA.getLocReg(), VA);
|
|
|
|
else if (VA.isMemLoc()) {
|
2016-12-06 06:20:32 +08:00
|
|
|
unsigned Size = VA.getValVT() == MVT::iPTR
|
|
|
|
? DL.getPointerSize()
|
2016-12-07 05:02:19 +08:00
|
|
|
: alignTo(VA.getValVT().getSizeInBits(), 8) / 8;
|
2016-12-05 18:40:33 +08:00
|
|
|
unsigned Offset = VA.getLocMemOffset();
|
|
|
|
MachinePointerInfo MPO;
|
|
|
|
unsigned StackAddr = Handler.getStackAddress(Size, Offset, MPO);
|
|
|
|
Handler.assignValueToAddress(Args[i].Reg, StackAddr, Size, MPO, VA);
|
|
|
|
} else {
|
|
|
|
// FIXME: Support byvals and other weirdness
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2016-12-13 18:46:12 +08:00
|
|
|
|
|
|
|
unsigned CallLowering::ValueHandler::extendRegister(unsigned ValReg,
|
|
|
|
CCValAssign &VA) {
|
|
|
|
LLT LocTy{VA.getLocVT()};
|
|
|
|
switch (VA.getLocInfo()) {
|
|
|
|
default: break;
|
|
|
|
case CCValAssign::Full:
|
|
|
|
case CCValAssign::BCvt:
|
|
|
|
// FIXME: bitconverting between vector types may or may not be a
|
|
|
|
// nop in big-endian situations.
|
|
|
|
return ValReg;
|
2017-10-10 04:07:43 +08:00
|
|
|
case CCValAssign::AExt: {
|
2016-12-13 18:46:12 +08:00
|
|
|
assert(!VA.getLocVT().isVector() && "unexpected vector extend");
|
2017-10-10 04:07:43 +08:00
|
|
|
auto MIB = MIRBuilder.buildAnyExt(LocTy, ValReg);
|
|
|
|
return MIB->getOperand(0).getReg();
|
|
|
|
}
|
2016-12-13 18:46:12 +08:00
|
|
|
case CCValAssign::SExt: {
|
|
|
|
unsigned NewReg = MRI.createGenericVirtualRegister(LocTy);
|
|
|
|
MIRBuilder.buildSExt(NewReg, ValReg);
|
|
|
|
return NewReg;
|
|
|
|
}
|
|
|
|
case CCValAssign::ZExt: {
|
|
|
|
unsigned NewReg = MRI.createGenericVirtualRegister(LocTy);
|
|
|
|
MIRBuilder.buildZExt(NewReg, ValReg);
|
|
|
|
return NewReg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
llvm_unreachable("unable to extend register");
|
|
|
|
}
|