summaryrefslogtreecommitdiff
path: root/lib/Target/ARM/ARMCallLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/ARM/ARMCallLowering.cpp')
-rw-r--r--lib/Target/ARM/ARMCallLowering.cpp118
1 files changed, 85 insertions, 33 deletions
diff --git a/lib/Target/ARM/ARMCallLowering.cpp b/lib/Target/ARM/ARMCallLowering.cpp
index a1a31e1e7fae..eab4b3b13f31 100644
--- a/lib/Target/ARM/ARMCallLowering.cpp
+++ b/lib/Target/ARM/ARMCallLowering.cpp
@@ -1,4 +1,4 @@
-//===-- llvm/lib/Target/ARM/ARMCallLowering.cpp - Call lowering -----------===//
+//===- llvm/lib/Target/ARM/ARMCallLowering.cpp - Call lowering ------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -6,30 +6,50 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-///
+//
/// \file
/// This file implements the lowering of LLVM calls to machine code calls for
/// GlobalISel.
-///
+//
//===----------------------------------------------------------------------===//
#include "ARMCallLowering.h"
-
#include "ARMBaseInstrInfo.h"
#include "ARMISelLowering.h"
#include "ARMSubtarget.h"
-
+#include "Utils/ARMBaseInfo.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/Analysis.h"
+#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
+#include "llvm/CodeGen/LowLevelType.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
+#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/MachineValueType.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/LowLevelTypeImpl.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <utility>
using namespace llvm;
-#ifndef LLVM_BUILD_GLOBAL_ISEL
-#error "This shouldn't be built without GISel"
-#endif
-
ARMCallLowering::ARMCallLowering(const ARMTargetLowering &TLI)
: CallLowering(&TLI) {}
@@ -63,12 +83,13 @@ static bool isSupportedType(const DataLayout &DL, const ARMTargetLowering &TLI,
}
namespace {
+
/// Helper class for values going out through an ABI boundary (used for handling
/// function return values and call parameters).
struct OutgoingValueHandler : public CallLowering::ValueHandler {
OutgoingValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
MachineInstrBuilder &MIB, CCAssignFn *AssignFn)
- : ValueHandler(MIRBuilder, MRI, AssignFn), MIB(MIB), StackSize(0) {}
+ : ValueHandler(MIRBuilder, MRI, AssignFn), MIB(MIB) {}
unsigned getStackAddress(uint64_t Size, int64_t Offset,
MachinePointerInfo &MPO) override {
@@ -157,9 +178,10 @@ struct OutgoingValueHandler : public CallLowering::ValueHandler {
}
MachineInstrBuilder &MIB;
- uint64_t StackSize;
+ uint64_t StackSize = 0;
};
-} // End anonymous namespace.
+
+} // end anonymous namespace
void ARMCallLowering::splitToValueTypes(
const ArgInfo &OrigArg, SmallVectorImpl<ArgInfo> &SplitArgs,
@@ -168,7 +190,7 @@ void ARMCallLowering::splitToValueTypes(
LLVMContext &Ctx = OrigArg.Ty->getContext();
const DataLayout &DL = MF.getDataLayout();
MachineRegisterInfo &MRI = MF.getRegInfo();
- const Function *F = MF.getFunction();
+ const Function &F = MF.getFunction();
SmallVector<EVT, 4> SplitVTs;
SmallVector<uint64_t, 4> Offsets;
@@ -196,7 +218,7 @@ void ARMCallLowering::splitToValueTypes(
bool NeedsConsecutiveRegisters =
TLI.functionArgumentNeedsConsecutiveRegisters(
- SplitTy, F->getCallingConv(), F->isVarArg());
+ SplitTy, F.getCallingConv(), F.isVarArg());
if (NeedsConsecutiveRegisters) {
Flags.setInConsecutiveRegs();
if (i == e - 1)
@@ -222,7 +244,7 @@ bool ARMCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder,
return true;
auto &MF = MIRBuilder.getMF();
- const auto &F = *MF.getFunction();
+ const auto &F = MF.getFunction();
auto DL = MF.getDataLayout();
auto &TLI = *getTLI<ARMTargetLowering>();
@@ -263,6 +285,7 @@ bool ARMCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
}
namespace {
+
/// Helper class for values coming in through an ABI boundary (used for handling
/// formal arguments and call return values).
struct IncomingValueHandler : public CallLowering::ValueHandler {
@@ -320,13 +343,26 @@ struct IncomingValueHandler : public CallLowering::ValueHandler {
assert(VA.isRegLoc() && "Value shouldn't be assigned to reg");
assert(VA.getLocReg() == PhysReg && "Assigning to the wrong reg?");
- assert(VA.getValVT().getSizeInBits() <= 64 && "Unsupported value size");
- assert(VA.getLocVT().getSizeInBits() <= 64 && "Unsupported location size");
+ auto ValSize = VA.getValVT().getSizeInBits();
+ auto LocSize = VA.getLocVT().getSizeInBits();
+
+ assert(ValSize <= 64 && "Unsupported value size");
+ assert(LocSize <= 64 && "Unsupported location size");
- // The necessary extensions are handled on the other side of the ABI
- // boundary.
markPhysRegUsed(PhysReg);
- MIRBuilder.buildCopy(ValVReg, PhysReg);
+ if (ValSize == LocSize) {
+ MIRBuilder.buildCopy(ValVReg, PhysReg);
+ } else {
+ assert(ValSize < LocSize && "Extensions not supported");
+
+ // We cannot create a truncating copy, nor a trunc of a physical register.
+ // Therefore, we need to copy the content of the physical register into a
+ // virtual one and then truncate that.
+ auto PhysRegToVReg =
+ MRI.createGenericVirtualRegister(LLT::scalar(LocSize));
+ MIRBuilder.buildCopy(PhysRegToVReg, PhysReg);
+ MIRBuilder.buildTrunc(ValVReg, PhysRegToVReg);
+ }
}
unsigned assignCustomValue(const ARMCallLowering::ArgInfo &Arg,
@@ -375,11 +411,18 @@ struct FormalArgHandler : public IncomingValueHandler {
MIRBuilder.getMBB().addLiveIn(PhysReg);
}
};
-} // End anonymous namespace
+
+} // end anonymous namespace
bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
const Function &F,
ArrayRef<unsigned> VRegs) const {
+ auto &TLI = *getTLI<ARMTargetLowering>();
+ auto Subtarget = TLI.getSubtarget();
+
+ if (Subtarget->isThumb())
+ return false;
+
// Quick exit if there aren't any args
if (F.arg_empty())
return true;
@@ -390,16 +433,13 @@ bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
auto &MF = MIRBuilder.getMF();
auto &MBB = MIRBuilder.getMBB();
auto DL = MF.getDataLayout();
- auto &TLI = *getTLI<ARMTargetLowering>();
-
- auto Subtarget = TLI.getSubtarget();
-
- if (Subtarget->isThumb())
- return false;
- for (auto &Arg : F.args())
+ for (auto &Arg : F.args()) {
if (!isSupportedType(DL, TLI, Arg.getType()))
return false;
+ if (Arg.hasByValOrInAllocaAttr())
+ return false;
+ }
CCAssignFn *AssignFn =
TLI.CCAssignFnForCall(F.getCallingConv(), F.isVarArg());
@@ -433,6 +473,7 @@ bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
}
namespace {
+
struct CallReturnHandler : public IncomingValueHandler {
CallReturnHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
MachineInstrBuilder MIB, CCAssignFn *AssignFn)
@@ -444,7 +485,8 @@ struct CallReturnHandler : public IncomingValueHandler {
MachineInstrBuilder MIB;
};
-} // End anonymous namespace.
+
+} // end anonymous namespace
bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
CallingConv::ID CallConv,
@@ -454,19 +496,26 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
MachineFunction &MF = MIRBuilder.getMF();
const auto &TLI = *getTLI<ARMTargetLowering>();
const auto &DL = MF.getDataLayout();
- const auto &STI = MF.getSubtarget();
+ const auto &STI = MF.getSubtarget<ARMSubtarget>();
const TargetRegisterInfo *TRI = STI.getRegisterInfo();
MachineRegisterInfo &MRI = MF.getRegInfo();
- if (MF.getSubtarget<ARMSubtarget>().genLongCalls())
+ if (STI.genLongCalls())
return false;
auto CallSeqStart = MIRBuilder.buildInstr(ARM::ADJCALLSTACKDOWN);
// Create the call instruction so we can add the implicit uses of arg
// registers, but don't insert it yet.
- auto MIB = MIRBuilder.buildInstrNoInsert(ARM::BLX).add(Callee).addRegMask(
- TRI->getCallPreservedMask(MF, CallConv));
+ bool isDirect = !Callee.isReg();
+ auto CallOpcode =
+ isDirect ? ARM::BL
+ : STI.hasV5TOps()
+ ? ARM::BLX
+ : STI.hasV4TOps() ? ARM::BX_CALL : ARM::BMOVPCRX_CALL;
+ auto MIB = MIRBuilder.buildInstrNoInsert(CallOpcode)
+ .add(Callee)
+ .addRegMask(TRI->getCallPreservedMask(MF, CallConv));
if (Callee.isReg()) {
auto CalleeReg = Callee.getReg();
if (CalleeReg && !TRI->isPhysicalRegister(CalleeReg))
@@ -483,6 +532,9 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
if (!Arg.IsFixed)
return false;
+ if (Arg.Flags.isByVal())
+ return false;
+
SmallVector<unsigned, 8> Regs;
splitToValueTypes(Arg, ArgInfos, MF, [&](unsigned Reg, uint64_t Offset) {
Regs.push_back(Reg);