2020-01-14 09:58:39 +01:00
|
|
|
//===-- VEISelLowering.cpp - VE DAG Lowering Implementation ---------------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the interfaces that VE uses to lower LLVM code into a
|
|
|
|
// selection DAG.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "VEISelLowering.h"
|
|
|
|
#include "VERegisterInfo.h"
|
|
|
|
#include "VETargetMachine.h"
|
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
|
|
#include "llvm/CodeGen/CallingConvLower.h"
|
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
|
|
|
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
|
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/KnownBits.h"
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "ve-lower"
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Calling Convention Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "VEGenCallingConv.inc"
|
|
|
|
|
|
|
|
bool VETargetLowering::CanLowerReturn(
|
|
|
|
CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
|
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
|
2020-01-16 09:24:41 +01:00
|
|
|
CCAssignFn *RetCC = RetCC_VE;
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
|
|
|
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
|
|
|
|
return CCInfo.CheckReturn(Outs, RetCC);
|
2020-01-14 09:58:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
VETargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
|
|
|
|
bool IsVarArg,
|
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
|
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
|
|
|
const SDLoc &DL, SelectionDAG &DAG) const {
|
2020-01-16 09:24:41 +01:00
|
|
|
// CCValAssign - represent the assignment of the return value to locations.
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
|
|
|
|
|
|
|
// CCState - Info about the registers and stack slot.
|
|
|
|
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
|
|
|
|
*DAG.getContext());
|
2020-01-14 09:58:39 +01:00
|
|
|
|
2020-01-16 09:24:41 +01:00
|
|
|
// Analyze return values.
|
|
|
|
CCInfo.AnalyzeReturn(Outs, RetCC_VE);
|
|
|
|
|
|
|
|
SDValue Flag;
|
2020-01-14 09:58:39 +01:00
|
|
|
SmallVector<SDValue, 4> RetOps(1, Chain);
|
2020-01-16 09:24:41 +01:00
|
|
|
|
|
|
|
// Copy the result values into the output registers.
|
|
|
|
for (unsigned i = 0; i != RVLocs.size(); ++i) {
|
|
|
|
CCValAssign &VA = RVLocs[i];
|
|
|
|
assert(VA.isRegLoc() && "Can only return in registers!");
|
|
|
|
SDValue OutVal = OutVals[i];
|
|
|
|
|
|
|
|
// Integer return values must be sign or zero extended by the callee.
|
|
|
|
switch (VA.getLocInfo()) {
|
|
|
|
case CCValAssign::Full:
|
|
|
|
break;
|
|
|
|
case CCValAssign::SExt:
|
|
|
|
OutVal = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), OutVal);
|
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
|
|
|
OutVal = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), OutVal);
|
|
|
|
break;
|
|
|
|
case CCValAssign::AExt:
|
|
|
|
OutVal = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), OutVal);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unknown loc info!");
|
|
|
|
}
|
|
|
|
|
2020-01-22 09:17:36 +01:00
|
|
|
assert(!VA.needsCustom() && "Unexpected custom lowering");
|
|
|
|
|
2020-01-16 09:24:41 +01:00
|
|
|
Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVal, Flag);
|
|
|
|
|
|
|
|
// Guarantee that all emitted copies are stuck together with flags.
|
|
|
|
Flag = Chain.getValue(1);
|
|
|
|
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
|
|
|
|
}
|
|
|
|
|
2020-01-14 09:58:39 +01:00
|
|
|
RetOps[0] = Chain; // Update chain.
|
2020-01-16 09:24:41 +01:00
|
|
|
|
|
|
|
// Add the flag if we have it.
|
|
|
|
if (Flag.getNode())
|
|
|
|
RetOps.push_back(Flag);
|
|
|
|
|
2020-01-14 09:58:39 +01:00
|
|
|
return DAG.getNode(VEISD::RET_FLAG, DL, MVT::Other, RetOps);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue VETargetLowering::LowerFormalArguments(
|
|
|
|
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
|
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
|
|
|
|
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
|
2020-01-16 09:24:41 +01:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
|
|
|
|
// Get the size of the preserved arguments area
|
|
|
|
unsigned ArgsPreserved = 64;
|
|
|
|
|
|
|
|
// Analyze arguments according to CC_VE.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
|
|
|
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
|
|
|
|
*DAG.getContext());
|
|
|
|
// Allocate the preserved area first.
|
|
|
|
CCInfo.AllocateStack(ArgsPreserved, 8);
|
|
|
|
// We already allocated the preserved area, so the stack offset computed
|
|
|
|
// by CC_VE would be correct now.
|
|
|
|
CCInfo.AnalyzeFormalArguments(Ins, CC_VE);
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
|
|
CCValAssign &VA = ArgLocs[i];
|
|
|
|
assert(VA.isRegLoc() && "TODO implement argument passing on stack");
|
|
|
|
if (VA.isRegLoc()) {
|
|
|
|
// This argument is passed in a register.
|
|
|
|
// All integer register arguments are promoted by the caller to i64.
|
|
|
|
|
|
|
|
// Create a virtual register for the promoted live-in value.
|
|
|
|
unsigned VReg =
|
|
|
|
MF.addLiveIn(VA.getLocReg(), getRegClassFor(VA.getLocVT()));
|
|
|
|
SDValue Arg = DAG.getCopyFromReg(Chain, DL, VReg, VA.getLocVT());
|
|
|
|
|
2020-01-22 09:17:36 +01:00
|
|
|
// Get the high bits for i32 struct elements.
|
|
|
|
if (VA.getValVT() == MVT::i32 && VA.needsCustom())
|
|
|
|
Arg = DAG.getNode(ISD::SRL, DL, VA.getLocVT(), Arg,
|
|
|
|
DAG.getConstant(32, DL, MVT::i32));
|
2020-01-16 09:24:41 +01:00
|
|
|
|
|
|
|
// The caller promoted the argument, so insert an Assert?ext SDNode so we
|
|
|
|
// won't promote the value again in this function.
|
|
|
|
switch (VA.getLocInfo()) {
|
|
|
|
case CCValAssign::SExt:
|
|
|
|
Arg = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Arg,
|
|
|
|
DAG.getValueType(VA.getValVT()));
|
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
|
|
|
Arg = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Arg,
|
|
|
|
DAG.getValueType(VA.getValVT()));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Truncate the register down to the argument type.
|
|
|
|
if (VA.isExtInLoc())
|
|
|
|
Arg = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Arg);
|
|
|
|
|
|
|
|
InVals.push_back(Arg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-14 09:58:39 +01:00
|
|
|
assert(!IsVarArg && "TODO implement var args");
|
|
|
|
return Chain;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME? Maybe this could be a TableGen attribute on some registers and
|
|
|
|
// this table could be generated automatically from RegInfo.
|
|
|
|
Register VETargetLowering::getRegisterByName(const char *RegName, LLT VT,
|
|
|
|
const MachineFunction &MF) const {
|
|
|
|
Register Reg = StringSwitch<Register>(RegName)
|
|
|
|
.Case("sp", VE::SX11) // Stack pointer
|
|
|
|
.Case("fp", VE::SX9) // Frame pointer
|
|
|
|
.Case("sl", VE::SX8) // Stack limit
|
|
|
|
.Case("lr", VE::SX10) // Link regsiter
|
|
|
|
.Case("tp", VE::SX14) // Thread pointer
|
|
|
|
.Case("outer", VE::SX12) // Outer regiser
|
|
|
|
.Case("info", VE::SX17) // Info area register
|
|
|
|
.Case("got", VE::SX15) // Global offset table register
|
|
|
|
.Case("plt", VE::SX16) // Procedure linkage table register
|
|
|
|
.Default(0);
|
|
|
|
|
|
|
|
if (Reg)
|
|
|
|
return Reg;
|
|
|
|
|
|
|
|
report_fatal_error("Invalid register name global variable");
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// TargetLowering Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-01-22 09:17:36 +01:00
|
|
|
/// isFPImmLegal - Returns true if the target can instruction select the
|
|
|
|
/// specified FP immediate natively. If false, the legalizer will
|
|
|
|
/// materialize the FP immediate as a load from a constant pool.
|
|
|
|
bool VETargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
|
|
|
|
bool ForCodeSize) const {
|
|
|
|
return VT == MVT::f32 || VT == MVT::f64;
|
|
|
|
}
|
|
|
|
|
2020-01-14 09:58:39 +01:00
|
|
|
VETargetLowering::VETargetLowering(const TargetMachine &TM,
|
|
|
|
const VESubtarget &STI)
|
|
|
|
: TargetLowering(TM), Subtarget(&STI) {
|
|
|
|
// Instructions which use registers as conditionals examine all the
|
|
|
|
// bits (as does the pseudo SELECT_CC expansion). I don't think it
|
|
|
|
// matters much whether it's ZeroOrOneBooleanContent, or
|
|
|
|
// ZeroOrNegativeOneBooleanContent, so, arbitrarily choose the
|
|
|
|
// former.
|
|
|
|
setBooleanContents(ZeroOrOneBooleanContent);
|
|
|
|
setBooleanVectorContents(ZeroOrOneBooleanContent);
|
|
|
|
|
|
|
|
// Set up the register classes.
|
2020-01-22 09:17:36 +01:00
|
|
|
addRegisterClass(MVT::i32, &VE::I32RegClass);
|
2020-01-14 09:58:39 +01:00
|
|
|
addRegisterClass(MVT::i64, &VE::I64RegClass);
|
2020-01-22 09:17:36 +01:00
|
|
|
addRegisterClass(MVT::f32, &VE::F32RegClass);
|
|
|
|
addRegisterClass(MVT::f64, &VE::I64RegClass);
|
2020-01-14 09:58:39 +01:00
|
|
|
|
|
|
|
setStackPointerRegisterToSaveRestore(VE::SX11);
|
|
|
|
|
|
|
|
// Set function alignment to 16 bytes
|
|
|
|
setMinFunctionAlignment(Align(16));
|
|
|
|
|
|
|
|
// VE stores all argument by 8 bytes alignment
|
|
|
|
setMinStackArgumentAlignment(Align(8));
|
|
|
|
|
|
|
|
computeRegisterProperties(Subtarget->getRegisterInfo());
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *VETargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|
|
|
switch ((VEISD::NodeType)Opcode) {
|
|
|
|
case VEISD::FIRST_NUMBER:
|
|
|
|
break;
|
|
|
|
case VEISD::RET_FLAG:
|
|
|
|
return "VEISD::RET_FLAG";
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
EVT VETargetLowering::getSetCCResultType(const DataLayout &, LLVMContext &,
|
|
|
|
EVT VT) const {
|
2020-01-22 15:45:42 +01:00
|
|
|
return MVT::i32;
|
2020-01-14 09:58:39 +01:00
|
|
|
}
|