diff --git a/llvm/lib/Target/CSKY/CMakeLists.txt b/llvm/lib/Target/CSKY/CMakeLists.txt --- a/llvm/lib/Target/CSKY/CMakeLists.txt +++ b/llvm/lib/Target/CSKY/CMakeLists.txt @@ -4,21 +4,36 @@ tablegen(LLVM CSKYGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM CSKYGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM CSKYGenCallingConv.inc -gen-callingconv) +tablegen(LLVM CSKYGenDAGISel.inc -gen-dag-isel) tablegen(LLVM CSKYGenInstrInfo.inc -gen-instr-info) tablegen(LLVM CSKYGenMCCodeEmitter.inc -gen-emitter) +tablegen(LLVM CSKYGenMCPseudoLowering.inc -gen-pseudo-lowering) tablegen(LLVM CSKYGenRegisterInfo.inc -gen-register-info) tablegen(LLVM CSKYGenSubtargetInfo.inc -gen-subtarget) add_public_tablegen_target(CSKYCommonTableGen) add_llvm_target(CSKYCodeGen + CSKYAsmPrinter.cpp + CSKYFrameLowering.cpp + CSKYInstrInfo.cpp + CSKYISelDAGToDAG.cpp + CSKYISelLowering.cpp + CSKYMCInstLower.cpp + CSKYRegisterInfo.cpp CSKYSubtarget.cpp CSKYTargetMachine.cpp LINK_COMPONENTS + Analysis + AsmPrinter Core CodeGen + CSKYDesc CSKYInfo + MC + SelectionDAG Support Target diff --git a/llvm/lib/Target/CSKY/CSKY.h b/llvm/lib/Target/CSKY/CSKY.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKY.h @@ -0,0 +1,27 @@ +//===-- CSKY.h - Top-level interface for CSKY--------------------*- C++ -*-===// +// +// 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 contains the entry points for global functions defined in the LLVM +// CSKY back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_CSKY_H +#define LLVM_LIB_TARGET_CSKY_CSKY_H + +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class CSKYTargetMachine; +class FunctionPass; + +FunctionPass *createCSKYISelDag(CSKYTargetMachine &TM); + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_CSKY_CSKY_H diff --git a/llvm/lib/Target/CSKY/CSKY.td b/llvm/lib/Target/CSKY/CSKY.td --- a/llvm/lib/Target/CSKY/CSKY.td +++ b/llvm/lib/Target/CSKY/CSKY.td @@ -87,6 +87,7 @@ //===----------------------------------------------------------------------===// include "CSKYRegisterInfo.td" +include "CSKYCallingConv.td" include "CSKYInstrInfo.td" //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/CSKY/CSKYAsmPrinter.h b/llvm/lib/Target/CSKY/CSKYAsmPrinter.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYAsmPrinter.h @@ -0,0 +1,40 @@ +//===-- CSKYAsmPrinter.h - CSKY implementation of AsmPrinter ----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_CSKYASMPRINTER_H +#define LLVM_LIB_TARGET_CSKY_CSKYASMPRINTER_H + +#include "CSKYMCInstLower.h" +#include "CSKYSubtarget.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/MC/MCDirectives.h" + +namespace llvm { +class LLVM_LIBRARY_VISIBILITY CSKYAsmPrinter : public AsmPrinter { + CSKYMCInstLower MCInstLowering; + + const CSKYSubtarget *Subtarget; + +public: + explicit CSKYAsmPrinter(TargetMachine &TM, + std::unique_ptr Streamer); + + StringRef getPassName() const override { return "CSKY Assembly Printer"; } + + /// tblgen'erated driver function for lowering simple MI->MC + /// pseudo instructions. + bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, + const MachineInstr *MI); + + void emitInstruction(const MachineInstr *MI) override; + + bool runOnMachineFunction(MachineFunction &MF) override; +}; +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_CSKY_CSKYASMPRINTER_H diff --git a/llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp b/llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp @@ -0,0 +1,58 @@ +//===-- CSKYAsmPrinter.cpp - CSKY LLVM assembly writer --------------------===// +// +// 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 contains a printer that converts from our internal representation +// of machine-dependent LLVM code to the CSKY assembly language. +// +//===----------------------------------------------------------------------===// +#include "CSKYAsmPrinter.h" +#include "CSKY.h" +#include "CSKYTargetMachine.h" +#include "MCTargetDesc/CSKYInstPrinter.h" +#include "MCTargetDesc/CSKYMCExpr.h" +#include "TargetInfo/CSKYTargetInfo.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstBuilder.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/TargetRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "csky-asm-printer" + +CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM, + std::unique_ptr Streamer) + : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this) {} + +bool CSKYAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget(); + return AsmPrinter::runOnMachineFunction(MF); +} + +// Simple pseudo-instructions have their lowering (with expansion to real +// instructions) auto-generated. +#include "CSKYGenMCPseudoLowering.inc" + +void CSKYAsmPrinter::emitInstruction(const MachineInstr *MI) { + // Do any auto-generated pseudo lowerings. + if (emitPseudoExpansionLowering(*OutStreamer, MI)) + return; + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + EmitToStreamer(*OutStreamer, TmpInst); +} + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() { + RegisterAsmPrinter X(getTheCSKYTarget()); +} diff --git a/llvm/lib/Target/CSKY/CSKYCallingConv.h b/llvm/lib/Target/CSKY/CSKYCallingConv.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYCallingConv.h @@ -0,0 +1,63 @@ +//=== CSKYCallingConv.h - CSKY Custom Calling Convention Routines -*-C++-*-===// +// +// 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 contains the custom routines for the CSKY Calling Convention that +// aren't done by tablegen. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_CSKYCALLINGCONV_H +#define LLVM_LIB_TARGET_CSKY_CSKYCALLINGCONV_H + +#include "CSKY.h" +#include "CSKYSubtarget.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/IR/CallingConv.h" + +namespace llvm { + +static bool CC_CSKY_ABIV2_SOFT_64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) { + + static const MCPhysReg ArgGPRs[] = {CSKY::R0, CSKY::R1, CSKY::R2, CSKY::R3}; + Register Reg = State.AllocateReg(ArgGPRs); + LocVT = MVT::i32; + if (!Reg) { + unsigned StackOffset = State.AllocateStack(8, Align(4)); + State.addLoc( + CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo)); + return true; + } + if (!State.AllocateReg(ArgGPRs)) + State.AllocateStack(4, Align(4)); + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + return true; +} + +static bool Ret_CSKY_ABIV2_SOFT_64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) { + + static const MCPhysReg ArgGPRs[] = {CSKY::R0, CSKY::R1}; + Register Reg = State.AllocateReg(ArgGPRs); + LocVT = MVT::i32; + if (!Reg) + return false; + + if (!State.AllocateReg(ArgGPRs)) + return false; + + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + return true; +} + +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/CSKY/CSKYCallingConv.td b/llvm/lib/Target/CSKY/CSKYCallingConv.td new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYCallingConv.td @@ -0,0 +1,82 @@ +//===-- CSKYCallingConv.td - Calling Conventions CSKY ----*- tablegen -*---===// +// +// 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 describes the calling conventions for the CSKY architecture. +// +//===----------------------------------------------------------------------===// + +def CSR_I32 : CalleeSavedRegs<(add R8, R15, (sequence "R%u", 4, 7), + (sequence "R%u", 9, 11), (sequence "R%u", 16, 17), R28)>; +def CSR_GPR_FPR32 : CalleeSavedRegs<(add CSR_I32, (sequence "F%u_32", 8, 15))>; +def CSR_GPR_FPR64 : CalleeSavedRegs<(add CSR_I32, + (sequence "F%u_64", 8, 15))>; + +// Interrupt handler needs to save/restore all registers that are used, +// both Caller and Callee saved registers. +def CSR_GPR_ISR : CalleeSavedRegs<(add R8, R15, + (sequence "R%u", 0, 3), + (sequence "R%u", 4, 7), + (sequence "R%u", 9, 13), + (sequence "R%u", 16, 31))>; + +def CSR_GPR_FPR32_ISR: CalleeSavedRegs<(add CSR_GPR_ISR, + (sequence "F%u_32", 0, 15))>; +def CSR_GPR_FPR64_ISR: CalleeSavedRegs<(add CSR_GPR_ISR, + (sequence "F%u_64", 0, 15))>; + +def CSR_GPR_FPR32v3_ISR: CalleeSavedRegs<(add CSR_GPR_FPR32_ISR, + (sequence "F%u_32", 16, 31))>; +def CSR_GPR_FPR64v3_ISR: CalleeSavedRegs<(add CSR_GPR_FPR64_ISR, + (sequence "F%u_64", 16, 31))>; + +// Needed for implementation of CSKYRegisterInfo::getNoPreservedMask() +def CSR_NoRegs : CalleeSavedRegs<(add)>; + +def CC_CSKY_ABIV2_SOFT : CallingConv<[ + // DSP types + CCIfType<[v2i16, v4i8], CCAssignToReg<[R0, R1, R2, R3]>>, + CCIfType<[v2i16, v4i8], CCAssignToStack<4, 4>>, + CCIfType<[i8, i16], CCPromoteToType>, + CCIfType<[f32], CCAssignToReg<[R0, R1, R2, R3]>>, + CCIfType<[f32], CCAssignToStack<4, 4>>, + CCIfType<[i32], CCAssignToReg<[R0, R1, R2, R3]>>, + CCIfType<[i32], CCAssignToStack<4, 4>>, + CCIfType<[f64], CCCustom<"CC_CSKY_ABIV2_SOFT_64">>, + CCIfType<[f64], CCAssignToStack<8, 4>> +]>; + +def RetCC_CSKY_ABIV2_SOFT : CallingConv<[ + // DSP types + CCIfType<[v2i16, v4i8], CCAssignToReg<[R0, R1]>>, + CCIfType<[i8, i16], CCPromoteToType>, + CCIfType<[f32], CCBitConvertToType>, + CCIfType<[i32], CCAssignToReg<[R0, R1]>>, + CCIfType<[f64], CCCustom<"Ret_CSKY_ABIV2_SOFT_64">> +]>; + +def CC_CSKY_ABIV2_FP : CallingConv<[ + // DSP types + CCIfType<[v2i16, v4i8], CCAssignToReg<[R0, R1, R2, R3]>>, + CCIfType<[v2i16, v4i8], CCAssignToStack<4, 4>>, + CCIfType<[i8, i16], CCPromoteToType>, + CCIfType<[i32], CCAssignToReg<[R0, R1, R2, R3]>>, + CCIfType<[i32], CCAssignToStack<4, 4>>, + CCIfType<[f32], CCAssignToReg<[F0_32, F1_32, F2_32, F3_32]>>, + CCIfType<[f32], CCAssignToStack<4, 4>>, + CCIfType<[f64], CCAssignToReg<[F0_64, F1_64, F2_64, F3_64]>>, + CCIfType<[f64], CCAssignToStack<8, 4>> +]>; + +def RetCC_CSKY_ABIV2_FP : CallingConv<[ + // DSP types + CCIfType<[v2i16, v4i8], CCAssignToReg<[R0, R1]>>, + CCIfType<[i8, i16], CCPromoteToType>, + CCIfType<[i32], CCAssignToReg<[R0, R1]>>, + CCIfType<[f32], CCAssignToReg<[F0_32]>>, + CCIfType<[f64], CCAssignToReg<[F0_64]>> +]>; \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/CSKYFrameLowering.h b/llvm/lib/Target/CSKY/CSKYFrameLowering.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYFrameLowering.h @@ -0,0 +1,38 @@ +//===-- CSKYFrameLowering.h - Define frame lowering for CSKY -*- C++ -*--===// +// +// 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 class implements CSKY-specific bits of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_CSKYFRAMELOWERING_H +#define LLVM_LIB_TARGET_CSKY_CSKYFRAMELOWERING_H + +#include "llvm/CodeGen/TargetFrameLowering.h" + +namespace llvm { +class CSKYSubtarget; + +class CSKYFrameLowering : public TargetFrameLowering { + const CSKYSubtarget &STI; + +public: + explicit CSKYFrameLowering(const CSKYSubtarget &STI) + : TargetFrameLowering(StackGrowsDown, + /*StackAlignment=*/Align(4), + /*LocalAreaOffset=*/0), + STI(STI) {} + + void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + + bool hasFP(const MachineFunction &MF) const override; + bool hasBP(const MachineFunction &MF) const; +}; +} // namespace llvm +#endif diff --git a/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp b/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp @@ -0,0 +1,57 @@ +//===-- CSKYFrameLowering.cpp - CSKY Frame Information ------------------===// +// +// 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 contains the CSKY implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "CSKYFrameLowering.h" +#include "CSKYSubtarget.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/MC/MCDwarf.h" + +using namespace llvm; + +#define DEBUG_TYPE "csky-frame-lowering" + +// Returns the register used to hold the frame pointer. +static Register getFPReg(const CSKYSubtarget &STI) { return CSKY::R8; } + +// To avoid the BP value clobbered by a function call, we need to choose a +// callee saved register to save the value. +static Register getBPReg(const CSKYSubtarget &STI) { return CSKY::R7; } + +bool CSKYFrameLowering::hasFP(const MachineFunction &MF) const { + const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); + + const MachineFrameInfo &MFI = MF.getFrameInfo(); + return MF.getTarget().Options.DisableFramePointerElim(MF) || + RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() || + MFI.isFrameAddressTaken(); +} + +bool CSKYFrameLowering::hasBP(const MachineFunction &MF) const { + const MachineFrameInfo &MFI = MF.getFrameInfo(); + + return MFI.hasVarSizedObjects(); +} + +void CSKYFrameLowering::emitPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + // FIXME: Implement this when we have function calls +} + +void CSKYFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + // FIXME: Implement this when we have function calls +} \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp b/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp @@ -0,0 +1,75 @@ +//===-- CSKYISelDAGToDAG.cpp - A dag to dag inst selector for CSKY---------===// +// +// 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 defines an instruction selector for the CSKY target. +// +//===----------------------------------------------------------------------===// + +#include "CSKY.h" +#include "CSKYSubtarget.h" +#include "CSKYTargetMachine.h" +#include "MCTargetDesc/CSKYMCTargetDesc.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/SelectionDAGISel.h" + +using namespace llvm; + +#define DEBUG_TYPE "csky-isel" + +namespace { +class CSKYDAGToDAGISel : public SelectionDAGISel { + const CSKYSubtarget *Subtarget; + +public: + explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM) : SelectionDAGISel(TM) {} + + StringRef getPassName() const override { + return "CSKY DAG->DAG Pattern Instruction Selection"; + } + + bool runOnMachineFunction(MachineFunction &MF) override { + // Reset the subtarget each time through. + Subtarget = &MF.getSubtarget(); + SelectionDAGISel::runOnMachineFunction(MF); + return true; + } + + void Select(SDNode *N) override; + +#include "CSKYGenDAGISel.inc" +}; +} // namespace + +void CSKYDAGToDAGISel::Select(SDNode *N) { + // If we have a custom node, we have already selected + if (N->isMachineOpcode()) { + LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n"); + N->setNodeId(-1); + return; + } + + SDLoc Dl(N); + unsigned Opcode = N->getOpcode(); + bool IsSelected = false; + + switch (Opcode) { + default: + break; + // FIXME: Add selection nodes needed later. + } + + if (IsSelected) + return; + + // Select the default instruction. + SelectCode(N); +} + +FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) { + return new CSKYDAGToDAGISel(TM); +} diff --git a/llvm/lib/Target/CSKY/CSKYISelLowering.h b/llvm/lib/Target/CSKY/CSKYISelLowering.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYISelLowering.h @@ -0,0 +1,69 @@ +//===-- CSKYISelLowering.cpp - CSKY 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 defines the interfaces that CSKY uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_CSKYISELLOWERING_H +#define LLVM_LIB_TARGET_CSKY_CSKYISELLOWERING_H + +#include "MCTargetDesc/CSKYBaseInfo.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/TargetLowering.h" + +namespace llvm { +class CSKYSubtarget; + +namespace CSKYISD { +enum NodeType : unsigned { + FIRST_NUMBER = ISD::BUILTIN_OP_END, + NIE, + NIR, + RET, + BITCAST_TO_LOHI +}; +} + +class CSKYTargetLowering : public TargetLowering { + const CSKYSubtarget &Subtarget; + +public: + explicit CSKYTargetLowering(const TargetMachine &TM, + const CSKYSubtarget &STI); + + EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, + EVT VT) const override; + +private: + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, + const SDLoc &DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; + + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, + bool IsVarArg, + const SmallVectorImpl &Outs, + LLVMContext &Context) const override; + + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, const SDLoc &DL, + SelectionDAG &DAG) const override; + + const char *getTargetNodeName(unsigned Opcode) const override; + + CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; + CCAssignFn *CCAssignFnForReturn(CallingConv::ID CC, bool IsVarArg) const; +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_CSKY_CSKYISELLOWERING_H diff --git a/llvm/lib/Target/CSKY/CSKYISelLowering.cpp b/llvm/lib/Target/CSKY/CSKYISelLowering.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYISelLowering.cpp @@ -0,0 +1,346 @@ +//===-- CSKYISelLowering.cpp - CSKY 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 defines the interfaces that CSKY uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#include "CSKYISelLowering.h" +#include "CSKYCallingConv.h" +#include "CSKYMachineFunctionInfo.h" +#include "CSKYRegisterInfo.h" +#include "CSKYSubtarget.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/Support/Debug.h" + +using namespace llvm; + +#define DEBUG_TYPE "csky-isel-lowering" + +STATISTIC(NumTailCalls, "Number of tail calls"); + +#include "CSKYGenCallingConv.inc" + +static const MCPhysReg GPRArgRegs[] = {CSKY::R0, CSKY::R1, CSKY::R2, CSKY::R3}; + +CSKYTargetLowering::CSKYTargetLowering(const TargetMachine &TM, + const CSKYSubtarget &STI) + : TargetLowering(TM), Subtarget(STI) { + // Register Class + addRegisterClass(MVT::i32, &CSKY::GPRRegClass); + + // Compute derived properties from the register classes. + computeRegisterProperties(STI.getRegisterInfo()); + + setBooleanContents(UndefinedBooleanContent); + setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); + + // TODO: Add atomic support fully. + setMaxAtomicSizeInBitsSupported(0); + + setStackPointerRegisterToSaveRestore(CSKY::R14); + const Align FunctionAlignment(2); + setMinFunctionAlignment(FunctionAlignment); + setSchedulingPreference(Sched::Source); +} + +EVT CSKYTargetLowering::getSetCCResultType(const DataLayout &DL, + LLVMContext &Context, EVT VT) const { + if (!VT.isVector()) + return MVT::i32; + + return VT.changeVectorElementTypeToInteger(); +} + +static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, + const CCValAssign &VA, const SDLoc &DL) { + EVT LocVT = VA.getLocVT(); + + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unexpected CCValAssign::LocInfo"); + case CCValAssign::Full: + break; + case CCValAssign::BCvt: + Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val); + break; + } + return Val; +} + +static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, + const CCValAssign &VA, const SDLoc &DL) { + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unexpected CCValAssign::LocInfo"); + case CCValAssign::Full: + break; + case CCValAssign::BCvt: + Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val); + break; + } + return Val; +} + +static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget, + SelectionDAG &DAG, SDValue Chain, + const CCValAssign &VA, const SDLoc &DL) { + MachineFunction &MF = DAG.getMachineFunction(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + EVT LocVT = VA.getLocVT(); + SDValue Val; + const TargetRegisterClass *RC; + + switch (LocVT.getSimpleVT().SimpleTy) { + default: + llvm_unreachable("Unexpected register type"); + case MVT::i32: + RC = &CSKY::GPRRegClass; + break; + } + + Register VReg = RegInfo.createVirtualRegister(RC); + RegInfo.addLiveIn(VA.getLocReg(), VReg); + Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT); + + return convertLocVTToValVT(DAG, Val, VA, DL); +} + +static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, + const CCValAssign &VA, const SDLoc &DL) { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + EVT LocVT = VA.getLocVT(); + EVT ValVT = VA.getValVT(); + EVT PtrVT = MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)); + int FI = MFI.CreateFixedObject(ValVT.getSizeInBits() / 8, + VA.getLocMemOffset(), /*Immutable=*/true); + SDValue FIN = DAG.getFrameIndex(FI, PtrVT); + SDValue Val; + + ISD::LoadExtType ExtType; + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unexpected CCValAssign::LocInfo"); + case CCValAssign::Full: + case CCValAssign::BCvt: + ExtType = ISD::NON_EXTLOAD; + break; + } + Val = DAG.getExtLoad( + ExtType, DL, LocVT, Chain, FIN, + MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT); + return Val; +} + +// Transform physical registers into virtual registers. +SDValue CSKYTargetLowering::LowerFormalArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl &InVals) const { + + switch (CallConv) { + default: + report_fatal_error("Unsupported calling convention"); + case CallingConv::C: + case CallingConv::Fast: + break; + } + + MachineFunction &MF = DAG.getMachineFunction(); + + // Used with vargs to acumulate store chains. + std::vector OutChains; + + // Assign locations to all of the incoming arguments. + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); + + CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, IsVarArg)); + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + SDValue ArgValue; + + if (VA.isRegLoc()) + ArgValue = unpackFromRegLoc(Subtarget, DAG, Chain, VA, DL); + else + ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL); + + InVals.push_back(ArgValue); + } + + if (IsVarArg) { + const unsigned XLenInBytes = 4; + const MVT XLenVT = MVT::i32; + + ArrayRef ArgRegs = makeArrayRef(GPRArgRegs); + unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs); + const TargetRegisterClass *RC = &CSKY::GPRRegClass; + MachineFrameInfo &MFI = MF.getFrameInfo(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + CSKYMachineFunctionInfo *CSKYFI = MF.getInfo(); + + // Offset of the first variable argument from stack pointer, and size of + // the vararg save area. For now, the varargs save area is either zero or + // large enough to hold a0-a4. + int VaArgOffset, VarArgsSaveSize; + + // If all registers are allocated, then all varargs must be passed on the + // stack and we don't need to save any argregs. + if (ArgRegs.size() == Idx) { + VaArgOffset = CCInfo.getNextStackOffset(); + VarArgsSaveSize = 0; + } else { + VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx); + VaArgOffset = -VarArgsSaveSize; + } + + // Record the frame index of the first variable argument + // which is a value necessary to VASTART. + int FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true); + CSKYFI->setVarArgsFrameIndex(FI); + + // Copy the integer registers that may have been used for passing varargs + // to the vararg save area. + for (unsigned I = Idx; I < ArgRegs.size(); + ++I, VaArgOffset += XLenInBytes) { + const Register Reg = RegInfo.createVirtualRegister(RC); + RegInfo.addLiveIn(ArgRegs[I], Reg); + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, XLenVT); + FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true); + SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, + MachinePointerInfo::getFixedStack(MF, FI)); + cast(Store.getNode()) + ->getMemOperand() + ->setValue((Value *)nullptr); + OutChains.push_back(Store); + } + CSKYFI->setVarArgsSaveSize(VarArgsSaveSize); + } + + // All stores are grouped in one node to allow the matching between + // the size of Ins and InVals. This only happens for vararg functions. + if (!OutChains.empty()) { + OutChains.push_back(Chain); + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); + } + + return Chain; +} + +bool CSKYTargetLowering::CanLowerReturn( + CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, + const SmallVectorImpl &Outs, LLVMContext &Context) const { + SmallVector CSKYLocs; + CCState CCInfo(CallConv, IsVarArg, MF, CSKYLocs, Context); + return CCInfo.CheckReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg)); +} + +SDValue +CSKYTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + const SDLoc &DL, SelectionDAG &DAG) const { + // Stores the assignment of the return value to a location. + SmallVector CSKYLocs; + + // Info about the registers and stack slot. + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), CSKYLocs, + *DAG.getContext()); + CCInfo.AnalyzeReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg)); + + SDValue Glue; + SmallVector RetOps(1, Chain); + + // Copy the result values into the output registers. + for (unsigned i = 0, e = CSKYLocs.size(); i < e; ++i) { + SDValue Val = OutVals[i]; + CCValAssign &VA = CSKYLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64; + + if (IsF64OnCSKY) { + + assert(VA.isRegLoc() && "Expected return via registers"); + SDValue Split64 = DAG.getNode(CSKYISD::BITCAST_TO_LOHI, DL, + DAG.getVTList(MVT::i32, MVT::i32), Val); + SDValue Lo = Split64.getValue(0); + SDValue Hi = Split64.getValue(1); + + Register RegLo = VA.getLocReg(); + assert(RegLo < CSKY::R31 && "Invalid register pair"); + Register RegHi = RegLo + 1; + + Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue); + Glue = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(RegLo, MVT::i32)); + Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue); + Glue = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(RegHi, MVT::i32)); + } else { + // Handle a 'normal' return. + Val = convertValVTToLocVT(DAG, Val, VA, DL); + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue); + + // Guarantee that all emitted copies are stuck together. + Glue = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + } + + RetOps[0] = Chain; // Update chain. + + // Add the glue node if we have it. + if (Glue.getNode()) { + RetOps.push_back(Glue); + } + + // Interrupt service routines use different return instructions. + if (DAG.getMachineFunction().getFunction().hasFnAttribute("interrupt")) + return DAG.getNode(CSKYISD::NIR, DL, MVT::Other, RetOps); + + return DAG.getNode(CSKYISD::RET, DL, MVT::Other, RetOps); +} + +CCAssignFn *CSKYTargetLowering::CCAssignFnForReturn(CallingConv::ID CC, + bool IsVarArg) const { + if (IsVarArg || !Subtarget.useHardFloatABI()) + return RetCC_CSKY_ABIV2_SOFT; + else + return RetCC_CSKY_ABIV2_FP; +} + +CCAssignFn *CSKYTargetLowering::CCAssignFnForCall(CallingConv::ID CC, + bool IsVarArg) const { + if (IsVarArg || !Subtarget.useHardFloatABI()) + return CC_CSKY_ABIV2_SOFT; + else + return CC_CSKY_ABIV2_FP; +} + +const char *CSKYTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + default: + llvm_unreachable("unknown CSKYISD node"); + case CSKYISD::NIE: + return "CSKYISD::NIE"; + case CSKYISD::NIR: + return "CSKYISD::NIR"; + case CSKYISD::RET: + return "CSKYISD::RET"; + case CSKYISD::BITCAST_TO_LOHI: + return "CSKYISD::BITCAST_TO_LOHI"; + } +} diff --git a/llvm/lib/Target/CSKY/CSKYInstrInfo.h b/llvm/lib/Target/CSKY/CSKYInstrInfo.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYInstrInfo.h @@ -0,0 +1,36 @@ +//===-- CSKYInstrInfo.h - CSKY Instruction Information --------*- C++ -*---===// +// +// 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 contains the CSKY implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_CSKYINSTRINFO_H +#define LLVM_LIB_TARGET_CSKY_CSKYINSTRINFO_H + +#include "MCTargetDesc/CSKYMCTargetDesc.h" +#include "llvm/CodeGen/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "CSKYGenInstrInfo.inc" + +namespace llvm { + +class CSKYSubtarget; + +class CSKYInstrInfo : public CSKYGenInstrInfo { +protected: + const CSKYSubtarget &STI; + +public: + explicit CSKYInstrInfo(CSKYSubtarget &STI); +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_CSKY_CSKYINSTRINFO_H diff --git a/llvm/lib/Target/CSKY/CSKYInstrInfo.cpp b/llvm/lib/Target/CSKY/CSKYInstrInfo.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYInstrInfo.cpp @@ -0,0 +1,25 @@ +//===-- CSKYInstrInfo.h - CSKY Instruction Information --------*- C++ -*---===// +// +// 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 contains the CSKY implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "CSKYInstrInfo.h" +#include "llvm/MC/MCContext.h" + +#define DEBUG_TYPE "csky-instr-info" + +using namespace llvm; + +#define GET_INSTRINFO_CTOR_DTOR +#include "CSKYGenInstrInfo.inc" + +CSKYInstrInfo::CSKYInstrInfo(CSKYSubtarget &STI) + : CSKYGenInstrInfo(CSKY::ADJCALLSTACKDOWN, CSKY::ADJCALLSTACKUP), STI(STI) { +} diff --git a/llvm/lib/Target/CSKY/CSKYMCInstLower.h b/llvm/lib/Target/CSKY/CSKYMCInstLower.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYMCInstLower.h @@ -0,0 +1,35 @@ +//===-- CSKYMCInstLower.cpp - Convert CSKY MachineInstr to an MCInst --------=// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_CSKYMCINSTLOWER_H +#define LLVM_LIB_TARGET_CSKY_CSKYMCINSTLOWER_H + +namespace llvm { +class AsmPrinter; +class MCContext; +class MachineInstr; +class MCInst; +class MachineOperand; +class MCOperand; +class MCSymbol; + +class CSKYMCInstLower { + MCContext &Ctx; + AsmPrinter &Printer; + +public: + CSKYMCInstLower(MCContext &Ctx, AsmPrinter &Printer); + + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const; + MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_CSKY_CSKYMCINSTLOWER_H diff --git a/llvm/lib/Target/CSKY/CSKYMCInstLower.cpp b/llvm/lib/Target/CSKY/CSKYMCInstLower.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYMCInstLower.cpp @@ -0,0 +1,117 @@ +//===-- CSKYMCInstLower.cpp - Convert CSKY MachineInstr to an MCInst --------=// +// +// 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 contains code to lower CSKY MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "CSKYMCInstLower.h" +#include "MCTargetDesc/CSKYBaseInfo.h" +#include "MCTargetDesc/CSKYMCExpr.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/MC/MCExpr.h" + +#define DEBUG_TYPE "csky-mcinst-lower" + +using namespace llvm; + +CSKYMCInstLower::CSKYMCInstLower(MCContext &Ctx, AsmPrinter &Printer) + : Ctx(Ctx), Printer(Printer) {} + +void CSKYMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (const MachineOperand &MO : MI->operands()) { + MCOperand MCOp; + if (lowerOperand(MO, MCOp)) + OutMI.addOperand(MCOp); + } +} + +MCOperand CSKYMCInstLower::lowerSymbolOperand(const MachineOperand &MO, + MCSymbol *Sym) const { + CSKYMCExpr::VariantKind Kind; + MCContext &Ctx = Printer.OutContext; + + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag."); + case CSKYII::MO_None: + Kind = CSKYMCExpr::VK_CSKY_None; + break; + case CSKYII::MO_GOT32: + Kind = CSKYMCExpr::VK_CSKY_GOT; + break; + case CSKYII::MO_GOTOFF: + Kind = CSKYMCExpr::VK_CSKY_GOTOFF; + break; + case CSKYII::MO_ADDR32: + Kind = CSKYMCExpr::VK_CSKY_ADDR; + break; + case CSKYII::MO_PLT32: + Kind = CSKYMCExpr::VK_CSKY_PLT; + break; + case CSKYII::MO_ADDR_HI16: + Kind = CSKYMCExpr::VK_CSKY_ADDR_HI16; + break; + case CSKYII::MO_ADDR_LO16: + Kind = CSKYMCExpr::VK_CSKY_ADDR_LO16; + break; + } + const MCExpr *ME = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx); + + if (Kind != CSKYMCExpr::VK_CSKY_None) + ME = CSKYMCExpr::create(ME, Kind, Ctx); + + return MCOperand::createExpr(ME); +} + +bool CSKYMCInstLower::lowerOperand(const MachineOperand &MO, + MCOperand &MCOp) const { + switch (MO.getType()) { + default: + llvm_unreachable("unknown operand type"); + case MachineOperand::MO_RegisterMask: + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::createImm(MO.getImm()); + break; + case MachineOperand::MO_Register: + if (MO.isImplicit()) + return false; + MCOp = MCOperand::createReg(MO.getReg()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::createExpr( + MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = lowerSymbolOperand(MO, Printer.getSymbol(MO.getGlobal())); + break; + case MachineOperand::MO_BlockAddress: + MCOp = lowerSymbolOperand( + MO, Printer.GetBlockAddressSymbol(MO.getBlockAddress())); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = lowerSymbolOperand( + MO, Printer.GetExternalSymbolSymbol(MO.getSymbolName())); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = lowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex())); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = lowerSymbolOperand(MO, Printer.GetJTISymbol(MO.getIndex())); + break; + case MachineOperand::MO_MCSymbol: + MCOp = lowerSymbolOperand(MO, MO.getMCSymbol()); + break; + } + return true; +} \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/CSKYMachineFunctionInfo.h b/llvm/lib/Target/CSKY/CSKYMachineFunctionInfo.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYMachineFunctionInfo.h @@ -0,0 +1,62 @@ +//=- CSKYMachineFunctionInfo.h - CSKY machine function info -------*- C++ -*-=// +// +// 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 declares CSKY-specific per-machine-function information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_CSKYMACHINEFUNCTIONINFO_H +#define LLVM_LIB_TARGET_CSKY_CSKYMACHINEFUNCTIONINFO_H + +#include "llvm/CodeGen/MachineFunction.h" + +namespace llvm { + +class CSKYMachineFunctionInfo : public MachineFunctionInfo { + MachineFunction &MF; + + Register GlobalBaseReg = 0; + bool SpillsCR = false; + + int VarArgsFrameIndex = 0; + unsigned VarArgsSaveSize = 0; + + int spillAreaSize = 0; + + bool LRSpilled = false; + + unsigned PICLabelUId = 0; + +public: + CSKYMachineFunctionInfo(MachineFunction &MF) : MF(MF) {} + + Register getGlobalBaseReg() const { return GlobalBaseReg; } + void setGlobalBaseReg(Register Reg) { GlobalBaseReg = Reg; } + + void setSpillsCR() { SpillsCR = true; } + bool isCRSpilled() const { return SpillsCR; } + + void setVarArgsFrameIndex(int v) { VarArgsFrameIndex = v; } + int getVarArgsFrameIndex() { return VarArgsFrameIndex; } + + unsigned getVarArgsSaveSize() const { return VarArgsSaveSize; } + void setVarArgsSaveSize(int Size) { VarArgsSaveSize = Size; } + + bool isLRSpilled() const { return LRSpilled; } + void setLRIsSpilled(bool s) { LRSpilled = s; } + + void setCalleeSaveAreaSize(int v) { spillAreaSize = v; } + int getCalleeSaveAreaSize() const { return spillAreaSize; } + + unsigned createPICLabelUId() { return ++PICLabelUId; } + void initPICLabelUId(unsigned UId) { PICLabelUId = UId; } +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_CSKY_CSKYMACHINEFUNCTIONINFO_H diff --git a/llvm/lib/Target/CSKY/CSKYRegisterInfo.h b/llvm/lib/Target/CSKY/CSKYRegisterInfo.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYRegisterInfo.h @@ -0,0 +1,45 @@ +//===-- CSKYRegisterInfo.h - CSKY Register Information Impl ---*- C++ -*---===// +// +// 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 contains the CSKY implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_CSKYREGISTERINFO_H +#define LLVM_LIB_TARGET_CSKY_CSKYREGISTERINFO_H + +#include "llvm/CodeGen/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "CSKYGenRegisterInfo.inc" + +namespace llvm { +class CSKYInstrInfo; + +class CSKYRegisterInfo : public CSKYGenRegisterInfo { +public: + CSKYRegisterInfo(); + + const uint32_t *getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID id) const override; + const uint32_t *getNoPreservedMask() const override; + + BitVector getReservedRegs(const MachineFunction &MF) const override; + + Register getFrameRegister(const MachineFunction &MF) const override; + + const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; + + void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, + unsigned FIOperandNum, + RegScavenger *RS) const override; +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_CSKY_CSKYREGISTERINFO_H diff --git a/llvm/lib/Target/CSKY/CSKYRegisterInfo.cpp b/llvm/lib/Target/CSKY/CSKYRegisterInfo.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYRegisterInfo.cpp @@ -0,0 +1,95 @@ +//===-- CSKYRegisterInfo.h - CSKY Register Information Impl ---*- C++ -*---===// +// +// 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 contains the CSKY implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "CSKYRegisterInfo.h" +#include "CSKY.h" +#include "CSKYSubtarget.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/MC/MCContext.h" + +#define GET_REGINFO_TARGET_DESC +#include "CSKYGenRegisterInfo.inc" + +using namespace llvm; + +CSKYRegisterInfo::CSKYRegisterInfo() + : CSKYGenRegisterInfo(CSKY::R15, 0, 0, 0) {} + +const uint32_t * +CSKYRegisterInfo::getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID Id) const { + const CSKYSubtarget &STI = MF.getSubtarget(); + return CSR_I32_RegMask; +} + +Register CSKYRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = getFrameLowering(MF); + return TFI->hasFP(MF) ? CSKY::R8 : CSKY::R14; +} + +BitVector CSKYRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + const CSKYFrameLowering *TFI = getFrameLowering(MF); + const CSKYSubtarget &STI = MF.getSubtarget(); + BitVector Reserved(getNumRegs()); + + // Reserve the base register if we need to allocate + // variable-sized objects at runtime. + if (TFI->hasBP(MF)) + markSuperRegs(Reserved, CSKY::R7); // bp + + if (TFI->hasFP(MF)) + markSuperRegs(Reserved, CSKY::R8); // fp + + if (!STI.hasE2()) { + for (unsigned i = 0; i < 6; i++) + markSuperRegs(Reserved, CSKY::R8 + i); // R8 - R13 + } + + markSuperRegs(Reserved, CSKY::R14); // sp + markSuperRegs(Reserved, CSKY::R15); // lr + + if (!STI.hasHighRegisters()) { + for (unsigned i = 0; i < 10; i++) + markSuperRegs(Reserved, CSKY::R16 + i); // R16 - R25 + } + + markSuperRegs(Reserved, CSKY::R26); + markSuperRegs(Reserved, CSKY::R27); + markSuperRegs(Reserved, CSKY::R28); // gp + markSuperRegs(Reserved, CSKY::R29); + markSuperRegs(Reserved, CSKY::R30); + markSuperRegs(Reserved, CSKY::R31); // tp + + assert(checkAllSuperRegsMarked(Reserved)); + return Reserved; +} + +const uint32_t *CSKYRegisterInfo::getNoPreservedMask() const { + return CSR_NoRegs_RegMask; +} + +const MCPhysReg * +CSKYRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + const CSKYSubtarget &STI = MF->getSubtarget(); + if (MF->getFunction().hasFnAttribute("interrupt")) { + return CSR_GPR_ISR_SaveList; + } + + return CSR_I32_SaveList; +} + +void CSKYRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const { + assert(SPAdj == 0 && "Unexpected non-zero SPAdj value"); +} \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/CSKYSubtarget.h b/llvm/lib/Target/CSKY/CSKYSubtarget.h --- a/llvm/lib/Target/CSKY/CSKYSubtarget.h +++ b/llvm/lib/Target/CSKY/CSKYSubtarget.h @@ -13,6 +13,10 @@ #ifndef LLVM_LIB_TARGET_CSKY_CSKYSUBTARGET_H #define LLVM_LIB_TARGET_CSKY_CSKYSUBTARGET_H +#include "CSKYFrameLowering.h" +#include "CSKYISelLowering.h" +#include "CSKYInstrInfo.h" +#include "CSKYRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGTargetInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Target/TargetMachine.h" @@ -32,6 +36,17 @@ CSKYTargetLowering TLInfo; SelectionDAGTargetInfo TSInfo; + bool UseHardFloat; + bool UseHardFloatABI; + bool HasFPUv2SingleFloat; + bool HasFPUv2DoubleFloat; + bool HasFPUv3SingleFloat; + bool HasFPUv3DoubleFloat; + + bool HasExtendLrw; + bool HasDoloop; + bool HasHighRegisters; + bool HasE1; bool HasE2; bool Has2E3; @@ -70,6 +85,20 @@ // Generated by inc file void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); + bool useHardFloatABI() const; + bool useHardFloat() const { return UseHardFloat; } + bool hasFPUv2SingleFloat() const { return HasFPUv2SingleFloat; } + bool hasFPUv2DoubleFloat() const { return HasFPUv2DoubleFloat; } + bool hasFPUv2() const { return HasFPUv2SingleFloat || HasFPUv2DoubleFloat; } + bool hasFPUv3SingleFloat() const { return HasFPUv3SingleFloat; } + bool hasFPUv3DoubleFloat() const { return HasFPUv3DoubleFloat; } + bool hasFPUv3() const { return HasFPUv3SingleFloat || HasFPUv3DoubleFloat; } + bool hasAnyFloatExt() const { return hasFPUv2() || hasFPUv3(); }; + + bool hasExtendLrw() const { return HasExtendLrw; } + bool hasDoloop() const { return HasDoloop; } + bool hasHighRegisters() const { return HasHighRegisters; } + bool hasE1() const { return HasE1; } bool hasE2() const { return HasE2; } bool has2E3() const { return Has2E3; } diff --git a/llvm/lib/Target/CSKY/CSKYSubtarget.cpp b/llvm/lib/Target/CSKY/CSKYSubtarget.cpp --- a/llvm/lib/Target/CSKY/CSKYSubtarget.cpp +++ b/llvm/lib/Target/CSKY/CSKYSubtarget.cpp @@ -29,6 +29,17 @@ if (TuneCPUName.empty()) TuneCPUName = CPUName; + UseHardFloat = false; + UseHardFloatABI = false; + HasFPUv2SingleFloat = false; + HasFPUv2DoubleFloat = false; + HasFPUv3SingleFloat = false; + HasFPUv3DoubleFloat = false; + + HasExtendLrw = false; + HasDoloop = false; + HasHighRegisters = false; + HasE1 = false; HasE2 = false; Has2E3 = false; @@ -50,3 +61,13 @@ : CSKYGenSubtargetInfo(TT, CPU, TuneCPU, FS), FrameLowering(initializeSubtargetDependencies(TT, CPU, TuneCPU, FS)), InstrInfo(*this), RegInfo(), TLInfo(TM, *this) {} + +bool CSKYSubtarget::useHardFloatABI() const { + auto FloatABI = getTargetLowering()->getTargetMachine().Options.FloatABIType; + + if (FloatABI == FloatABI::Default) + return UseHardFloatABI; + else + return FloatABI == FloatABI::Hard; +} + diff --git a/llvm/lib/Target/CSKY/CSKYTargetMachine.h b/llvm/lib/Target/CSKY/CSKYTargetMachine.h --- a/llvm/lib/Target/CSKY/CSKYTargetMachine.h +++ b/llvm/lib/Target/CSKY/CSKYTargetMachine.h @@ -20,6 +20,7 @@ class CSKYTargetMachine : public LLVMTargetMachine { std::unique_ptr TLOF; + mutable StringMap> SubtargetMap; public: CSKYTargetMachine(const Target &T, const Triple &TT, StringRef CPU, @@ -29,6 +30,12 @@ TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + const CSKYSubtarget *getSubtargetImpl(const Function &F) const override; + // DO NOT IMPLEMENT: There is no such thing as a valid default subtarget, + // subtargets are per-function entities based on the target-specific + // attributes of each function. + const CSKYSubtarget *getSubtargetImpl() const = delete; + TargetLoweringObjectFile *getObjFileLowering() const override { return TLOF.get(); } diff --git a/llvm/lib/Target/CSKY/CSKYTargetMachine.cpp b/llvm/lib/Target/CSKY/CSKYTargetMachine.cpp --- a/llvm/lib/Target/CSKY/CSKYTargetMachine.cpp +++ b/llvm/lib/Target/CSKY/CSKYTargetMachine.cpp @@ -11,9 +11,12 @@ //===----------------------------------------------------------------------===// #include "CSKYTargetMachine.h" +#include "CSKY.h" +#include "CSKYSubtarget.h" #include "TargetInfo/CSKYTargetInfo.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/MC/TargetRegistry.h" using namespace llvm; @@ -50,6 +53,34 @@ initAsmInfo(); } +const CSKYSubtarget * +CSKYTargetMachine::getSubtargetImpl(const Function &F) const { + Attribute CPUAttr = F.getFnAttribute("target-cpu"); + Attribute TuneAttr = F.getFnAttribute("tune-cpu"); + Attribute FSAttr = F.getFnAttribute("target-features"); + + std::string CPU = + CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU; + std::string TuneCPU = + TuneAttr.isValid() ? TuneAttr.getValueAsString().str() : CPU; + std::string FS = + FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS; + + std::string Key = CPU + TuneCPU + FS; + auto &I = SubtargetMap[Key]; + if (!I) { + // This needs to be done before we create a new subtarget since any + // creation will depend on the TM and the code generation flags on the + // function that reside in TargetOptions. + resetTargetOptions(F); + I = std::make_unique(TargetTriple, CPU, TuneCPU, FS, *this); + if (I->useHardFloat() && !I->hasAnyFloatExt()) + errs() << "Hard-float can't be used with current CPU," + " set to Soft-float\n"; + } + return I.get(); +} + namespace { class CSKYPassConfig : public TargetPassConfig { public: @@ -59,6 +90,8 @@ CSKYTargetMachine &getCSKYTargetMachine() const { return getTM(); } + + bool addInstSelector() override; }; } // namespace @@ -66,3 +99,9 @@ TargetPassConfig *CSKYTargetMachine::createPassConfig(PassManagerBase &PM) { return new CSKYPassConfig(*this, PM); } + +bool CSKYPassConfig::addInstSelector() { + addPass(createCSKYISelDag(getCSKYTargetMachine())); + + return false; +} diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYBaseInfo.h b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYBaseInfo.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYBaseInfo.h @@ -0,0 +1,70 @@ +//===-- CSKYBaseInfo.h - Top level definitions for CSKY ---*- C++ -*-------===// +// +// 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 contains small standalone helper functions and enum definitions for +// the CSKY target useful for the compiler back-end and the MC libraries. +// As such, it deliberately does not include references to LLVM core +// code gen types, passes, etc.. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYBASEINFO_H +#define LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYBASEINFO_H + +#include "MCTargetDesc/CSKYMCTargetDesc.h" +#include "llvm/MC/MCInstrDesc.h" + +namespace llvm { + +// CSKYII - This namespace holds all of the target specific flags that +// instruction info tracks. All definitions must match CSKYInstrFormats.td. +namespace CSKYII { + +enum AddrMode { + AddrModeNone = 0, + AddrMode32B = 1, // ld32.b, ld32.bs, st32.b, st32.bs, +4kb + AddrMode32H = 2, // ld32.h, ld32.hs, st32.h, st32.hs, +8kb + AddrMode32WD = 3, // ld32.w, st32.w, ld32.d, st32.d, +16kb + AddrMode16B = 4, // ld16.b, +32b + AddrMode16H = 5, // ld16.h, +64b + AddrMode16W = 6, // ld16.w, +128b or +1kb + AddrMode32SDF = 7, // flds, fldd, +1kb +}; + +// CSKY Specific MachineOperand Flags. +enum TOF { + MO_None = 0, + MO_ADDR32, + MO_GOT32, + MO_GOTOFF, + MO_PLT32, + MO_ADDR_HI16, + MO_ADDR_LO16, + + // Used to differentiate between target-specific "direct" flags and "bitmask" + // flags. A machine operand can only have one "direct" flag, but can have + // multiple "bitmask" flags. + MO_DIRECT_FLAG_MASK = 15 +}; + +enum { + AddrModeMask = 0x1f, +}; + +} // namespace CSKYII + +namespace CSKYOp { +enum OperandType : unsigned { + OPERAND_BARESYMBOL = MCOI::OPERAND_FIRST_TARGET, + OPERAND_CONSTPOOL +}; +} // namespace CSKYOp + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYBASEINFO_H diff --git a/llvm/test/CodeGen/CSKY/base-i.ll b/llvm/test/CodeGen/CSKY/base-i.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/CSKY/base-i.ll @@ -0,0 +1,33 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -csky-no-aliases -mattr=+e2 < %s -mtriple=csky | FileCheck %s + +define i32 @addRR(i32 %x, i32 %y) { +; CHECK-LABEL: addRR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addu32 a0, a1, a0 +; CHECK-NEXT: rts32 +entry: + %add = add nsw i32 %y, %x + ret i32 %add +} + +define i32 @addRI(i32 %x) { +; CHECK-LABEL: addRI: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addi32 a0, a0, 10 +; CHECK-NEXT: rts32 +entry: + %add = add nsw i32 %x, 10 + ret i32 %add +} + +define i32 @addRI_X(i32 %x) { +; CHECK-LABEL: addRI_X: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movi32 a1, 4097 +; CHECK-NEXT: addu32 a0, a0, a1 +; CHECK-NEXT: rts32 +entry: + %add = add nsw i32 %x, 4097 + ret i32 %add +} diff --git a/llvm/test/CodeGen/CSKY/lit.local.cfg b/llvm/test/CodeGen/CSKY/lit.local.cfg new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/CSKY/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'CSKY' in config.root.targets: + config.unsupported = True