//===-- 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 &Outs, LLVMContext &Context) const { CCAssignFn *RetCC = RetCC_VE; SmallVector RVLocs; CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); return CCInfo.CheckReturn(Outs, RetCC); } SDValue VETargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const { // CCValAssign - represent the assignment of the return value to locations. SmallVector RVLocs; // CCState - Info about the registers and stack slot. CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, *DAG.getContext()); // Analyze return values. CCInfo.AnalyzeReturn(Outs, RetCC_VE); SDValue Flag; SmallVector RetOps(1, Chain); // 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!"); } assert(!VA.needsCustom() && "Unexpected custom lowering"); 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())); } RetOps[0] = Chain; // Update chain. // Add the flag if we have it. if (Flag.getNode()) RetOps.push_back(Flag); return DAG.getNode(VEISD::RET_FLAG, DL, MVT::Other, RetOps); } SDValue VETargetLowering::LowerFormalArguments( SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); // Get the size of the preserved arguments area unsigned ArgsPreserved = 64; // Analyze arguments according to CC_VE. SmallVector 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()); // 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)); // 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; } } 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(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 //===----------------------------------------------------------------------===// /// 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; } 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. addRegisterClass(MVT::i32, &VE::I32RegClass); addRegisterClass(MVT::i64, &VE::I64RegClass); addRegisterClass(MVT::f32, &VE::F32RegClass); addRegisterClass(MVT::f64, &VE::I64RegClass); 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 { return MVT::i32; }