From 3346ce7832f711ad97b393453daed925695a3317 Mon Sep 17 00:00:00 2001 From: Hoernchen Date: Fri, 3 May 2013 19:11:36 +0200 Subject: [PATCH] initial commit --- CMakeLists.txt | 37 + CondMovPass.cpp | 81 ++ Epiphany.h | 42 + Epiphany.td | 60 ++ EpiphanyAsmPrinter.cpp | 333 ++++++++ EpiphanyAsmPrinter.h | 80 ++ EpiphanyCallingConv.td | 25 + EpiphanyFrameLowering.cpp | 563 +++++++++++++ EpiphanyFrameLowering.h | 106 +++ EpiphanyISelDAGToDAG.cpp | 266 ++++++ EpiphanyISelLowering.cpp | 1074 +++++++++++++++++++++++++ EpiphanyISelLowering.h | 155 ++++ EpiphanyInstrFormats.td | 93 +++ EpiphanyInstrInfo.cpp | 751 +++++++++++++++++ EpiphanyInstrInfo.h | 120 +++ EpiphanyInstrInfo.td | 612 ++++++++++++++ EpiphanyLSOptPass.cpp | 535 ++++++++++++ EpiphanyMCInstLower.cpp | 120 +++ EpiphanyMachineFunctionInfo.cpp | 18 + EpiphanyMachineFunctionInfo.h | 149 ++++ EpiphanyRegisterInfo.cpp | 166 ++++ EpiphanyRegisterInfo.h | 84 ++ EpiphanyRegisterInfo.td | 102 +++ EpiphanySchedule.td | 10 + EpiphanySelectionDAGInfo.cpp | 25 + EpiphanySelectionDAGInfo.h | 32 + EpiphanySubtarget.cpp | 41 + EpiphanySubtarget.h | 51 ++ EpiphanyTargetMachine.cpp | 95 +++ EpiphanyTargetMachine.h | 69 ++ EpiphanyTargetObjectFile.cpp | 24 + EpiphanyTargetObjectFile.h | 31 + InstPrinter/CMakeLists.txt | 8 + InstPrinter/EpiphanyInstPrinter.cpp | 118 +++ InstPrinter/EpiphanyInstPrinter.h | 72 ++ InstPrinter/LLVMBuild.txt | 24 + InstPrinter/Makefile | 15 + LLVMBuild.txt | 36 + MCTargetDesc/CMakeLists.txt | 9 + MCTargetDesc/EpiphanyMCAsmInfo.cpp | 41 + MCTargetDesc/EpiphanyMCAsmInfo.h | 27 + MCTargetDesc/EpiphanyMCExpr.cpp | 95 +++ MCTargetDesc/EpiphanyMCExpr.h | 82 ++ MCTargetDesc/EpiphanyMCTargetDesc.cpp | 175 ++++ MCTargetDesc/EpiphanyMCTargetDesc.h | 65 ++ MCTargetDesc/LLVMBuild.txt | 24 + MCTargetDesc/Makefile | 16 + Makefile | 30 + README.md | 2 +- README.txt | 2 + TargetInfo/CMakeLists.txt | 7 + TargetInfo/EpiphanyTargetInfo.cpp | 24 + TargetInfo/LLVMBuild.txt | 24 + TargetInfo/Makefile | 15 + Utils/CMakeLists.txt | 5 + Utils/EpiphanyBaseInfo.cpp | 71 ++ Utils/EpiphanyBaseInfo.h | 102 +++ Utils/LLVMBuild.txt | 23 + Utils/Makefile | 15 + 59 files changed, 7076 insertions(+), 1 deletion(-) create mode 100644 CMakeLists.txt create mode 100644 CondMovPass.cpp create mode 100644 Epiphany.h create mode 100644 Epiphany.td create mode 100644 EpiphanyAsmPrinter.cpp create mode 100644 EpiphanyAsmPrinter.h create mode 100644 EpiphanyCallingConv.td create mode 100644 EpiphanyFrameLowering.cpp create mode 100644 EpiphanyFrameLowering.h create mode 100644 EpiphanyISelDAGToDAG.cpp create mode 100644 EpiphanyISelLowering.cpp create mode 100644 EpiphanyISelLowering.h create mode 100644 EpiphanyInstrFormats.td create mode 100644 EpiphanyInstrInfo.cpp create mode 100644 EpiphanyInstrInfo.h create mode 100644 EpiphanyInstrInfo.td create mode 100644 EpiphanyLSOptPass.cpp create mode 100644 EpiphanyMCInstLower.cpp create mode 100644 EpiphanyMachineFunctionInfo.cpp create mode 100644 EpiphanyMachineFunctionInfo.h create mode 100644 EpiphanyRegisterInfo.cpp create mode 100644 EpiphanyRegisterInfo.h create mode 100644 EpiphanyRegisterInfo.td create mode 100644 EpiphanySchedule.td create mode 100644 EpiphanySelectionDAGInfo.cpp create mode 100644 EpiphanySelectionDAGInfo.h create mode 100644 EpiphanySubtarget.cpp create mode 100644 EpiphanySubtarget.h create mode 100644 EpiphanyTargetMachine.cpp create mode 100644 EpiphanyTargetMachine.h create mode 100644 EpiphanyTargetObjectFile.cpp create mode 100644 EpiphanyTargetObjectFile.h create mode 100644 InstPrinter/CMakeLists.txt create mode 100644 InstPrinter/EpiphanyInstPrinter.cpp create mode 100644 InstPrinter/EpiphanyInstPrinter.h create mode 100644 InstPrinter/LLVMBuild.txt create mode 100644 InstPrinter/Makefile create mode 100644 LLVMBuild.txt create mode 100644 MCTargetDesc/CMakeLists.txt create mode 100644 MCTargetDesc/EpiphanyMCAsmInfo.cpp create mode 100644 MCTargetDesc/EpiphanyMCAsmInfo.h create mode 100644 MCTargetDesc/EpiphanyMCExpr.cpp create mode 100644 MCTargetDesc/EpiphanyMCExpr.h create mode 100644 MCTargetDesc/EpiphanyMCTargetDesc.cpp create mode 100644 MCTargetDesc/EpiphanyMCTargetDesc.h create mode 100644 MCTargetDesc/LLVMBuild.txt create mode 100644 MCTargetDesc/Makefile create mode 100644 Makefile create mode 100644 README.txt create mode 100644 TargetInfo/CMakeLists.txt create mode 100644 TargetInfo/EpiphanyTargetInfo.cpp create mode 100644 TargetInfo/LLVMBuild.txt create mode 100644 TargetInfo/Makefile create mode 100644 Utils/CMakeLists.txt create mode 100644 Utils/EpiphanyBaseInfo.cpp create mode 100644 Utils/EpiphanyBaseInfo.h create mode 100644 Utils/LLVMBuild.txt create mode 100644 Utils/Makefile diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4585380 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,37 @@ +set(LLVM_TARGET_DEFINITIONS Epiphany.td) + +#tablegen(LLVM EpiphanyGenAsmMatcher.inc -gen-asm-matcher) +tablegen(LLVM EpiphanyGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM EpiphanyGenCallingConv.inc -gen-callingconv) +#tablegen(LLVM EpiphanyGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM EpiphanyGenInstrInfo.inc -gen-instr-info) +#tablegen(LLVM EpiphanyGenMCCodeEmitter.inc -gen-emitter -mc-emitter) +tablegen(LLVM EpiphanyGenMCPseudoLowering.inc -gen-pseudo-lowering) +tablegen(LLVM EpiphanyGenRegisterInfo.inc -gen-register-info) +tablegen(LLVM EpiphanyGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM EpiphanyGenSubtargetInfo.inc -gen-subtarget) +add_public_tablegen_target(EpiphanyCommonTableGen) + +add_llvm_target(EpiphanyCodeGen + EpiphanyAsmPrinter.cpp + EpiphanyFrameLowering.cpp + EpiphanyISelDAGToDAG.cpp + EpiphanyISelLowering.cpp + EpiphanyInstrInfo.cpp + EpiphanyMachineFunctionInfo.cpp + EpiphanyMCInstLower.cpp + EpiphanyRegisterInfo.cpp + EpiphanySelectionDAGInfo.cpp + EpiphanySubtarget.cpp + EpiphanyTargetMachine.cpp + EpiphanyTargetObjectFile.cpp + EpiphanyLSOptPass.cpp + CondMovPass.cpp + ) + +#add_subdirectory(AsmParser) +#add_subdirectory(Disassembler) +add_subdirectory(InstPrinter) +add_subdirectory(MCTargetDesc) +add_subdirectory(TargetInfo) +add_subdirectory(Utils) \ No newline at end of file diff --git a/CondMovPass.cpp b/CondMovPass.cpp new file mode 100644 index 0000000..d071ac1 --- /dev/null +++ b/CondMovPass.cpp @@ -0,0 +1,81 @@ +//===-- EpiphanyCondMovPass.cpp -----------------------===// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "epiphany_condmovpass" +#include "Epiphany.h" +#include "EpiphanyMachineFunctionInfo.h" +#include "EpiphanySubtarget.h" +#include "EpiphanyTargetMachine.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" + +using namespace llvm; + +namespace { + +class EpiphanyCondMovPass : public MachineFunctionPass { + +private: + EpiphanyTargetMachine& QTM; + + public: + static char ID; + EpiphanyCondMovPass(EpiphanyTargetMachine& TM) : MachineFunctionPass(ID), QTM(TM) {} + + const char *getPassName() const { + return "Epiphany movCC cleanup"; + } + bool runOnMachineFunction(MachineFunction &Fn); +}; + +char EpiphanyCondMovPass::ID = 0; + +bool EpiphanyCondMovPass::runOnMachineFunction(MachineFunction &Fn) { + bool modified = false; + // Loop over all of the basic blocks. + for(MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end(); MBBb != MBBe; ++MBBb) { + MachineBasicBlock* MBB = MBBb; + + std::vector killmeplease; + // Loop over all instructions. + for(MachineBasicBlock::iterator MII = MBB->begin(), E = MBB->end(); MII != E; ++MII){ + MachineInstr *MI = &*MII; + if((MI->getOpcode() == Epiphany::MOVww || MI->getOpcode() == Epiphany::MOVss) && MI->getOperand(0).isReg() && MI->getOperand(1).isReg() && MI->getOperand(0).getReg() == MI->getOperand(1).getReg()) + killmeplease.push_back(MI); + } + + if(!killmeplease.empty()){ + modified = true; + for (std::vector::iterator kb = killmeplease.begin(), ke = killmeplease.end(); kb != ke ; kb++) + (*kb)->eraseFromParent(); // we can safely do this because mov Rd, Rd is a nop with no side effects. + } + + } + return modified; +} + +}// namespace + + +//===----------------------------------------------------------------------===// +// Public Constructor Functions +//===----------------------------------------------------------------------===// + +FunctionPass *llvm::createEpiphanyCondMovPass(EpiphanyTargetMachine &TM) { + return new EpiphanyCondMovPass(TM); +} diff --git a/Epiphany.h b/Epiphany.h new file mode 100644 index 0000000..be352de --- /dev/null +++ b/Epiphany.h @@ -0,0 +1,42 @@ +//==-- Epiphany.h - Top-level interface for Epiphany representation -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the entry points for global functions defined in the LLVM +// Epiphany back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_EPIPHANY_H +#define LLVM_TARGET_EPIPHANY_H + +#include "MCTargetDesc/EpiphanyMCTargetDesc.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +class EpiphanyAsmPrinter; +class FunctionPass; +class EpiphanyTargetMachine; +class MachineInstr; +class MCInst; + +FunctionPass *createEpiphanyISelDAG(EpiphanyTargetMachine &TM, + CodeGenOpt::Level OptLevel); + +FunctionPass *createEpiphanyCondMovPass(EpiphanyTargetMachine &TM); + +FunctionPass *createEpiphanyLSOptPass(); + +void LowerEpiphanyMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, + EpiphanyAsmPrinter &AP); + + +} + +#endif diff --git a/Epiphany.td b/Epiphany.td new file mode 100644 index 0000000..1a7a13d --- /dev/null +++ b/Epiphany.td @@ -0,0 +1,60 @@ +//===- Epiphany.td - Describe the Epiphany Target Machine -------*- tblgen -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the top level entry point for the Epiphany target. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Epiphany Processors +// + +include "EpiphanySchedule.td" + +def : Processor<"generic", GenericItineraries, []>; + +//===----------------------------------------------------------------------===// +// Register File Description +//===----------------------------------------------------------------------===// + +include "EpiphanyRegisterInfo.td" + +include "EpiphanyCallingConv.td" + +//===----------------------------------------------------------------------===// +// Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "EpiphanyInstrInfo.td" + +def EpiphanyInstrInfo : InstrInfo; + +//===----------------------------------------------------------------------===// +// Assembly printer +//===----------------------------------------------------------------------===// + +def A64InstPrinter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + bit isMCAsmWriter = 1; +} + +//===----------------------------------------------------------------------===// +// Declare the target which we are implementing +//===----------------------------------------------------------------------===// + +def Epiphany : Target { + let InstructionSet = EpiphanyInstrInfo; + let AssemblyWriters = [A64InstPrinter]; +} diff --git a/EpiphanyAsmPrinter.cpp b/EpiphanyAsmPrinter.cpp new file mode 100644 index 0000000..5c00eea --- /dev/null +++ b/EpiphanyAsmPrinter.cpp @@ -0,0 +1,333 @@ +//===-- EpiphanyAsmPrinter.cpp - Print machine code to an Epiphany .s file --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format Epiphany assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "EpiphanyAsmPrinter.h" +#include "InstPrinter/EpiphanyInstPrinter.h" +#include "llvm/DebugInfo.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/Mangler.h" + +using namespace llvm; + +MachineLocation +EpiphanyAsmPrinter::getDebugValueLocation(const MachineInstr *MI) const { + // See emitFrameIndexDebugValue in InstrInfo for where this instruction is + // expected to be created. + assert(MI->getNumOperands() == 4 && MI->getOperand(0).isReg() + && MI->getOperand(1).isImm() && "unexpected custom DBG_VALUE"); + return MachineLocation(MI->getOperand(0).getReg(), + MI->getOperand(1).getImm()); +} + +/// Try to print a floating-point register as if it belonged to a specified +/// register-class. For example the inline asm operand modifier "b" requires its +/// argument to be printed as "bN". +static bool printModifiedFPRAsmOperand(const MachineOperand &MO, + const TargetRegisterInfo *TRI, + const TargetRegisterClass &RegClass, + raw_ostream &O) { + if (!MO.isReg()) + return true; + + for (MCRegAliasIterator AR(MO.getReg(), TRI, true); AR.isValid(); ++AR) { + if (RegClass.contains(*AR)) { + O << EpiphanyInstPrinter::getRegisterName(*AR); + return false; + } + } + return true; +} + +/// Implements the 'w' and 'x' inline asm operand modifiers, which print a GPR +/// with the obvious type and an immediate 0 as either wzr or xzr. +static bool printModifiedGPRAsmOperand(const MachineOperand &MO, + const TargetRegisterInfo *TRI, + const TargetRegisterClass &RegClass, + raw_ostream &O) { + char Prefix = &RegClass == &Epiphany::GPR32RegClass ? 'w' : 'x'; + + if (MO.isImm() && MO.getImm() == 0) { + O << Prefix << "zr"; + return false; + } else if (MO.isReg()) { + if (MO.getReg() == Epiphany::SP) { + O << (Prefix == 'x' ? "sp" : "wsp"); + return false; + } + + for (MCRegAliasIterator AR(MO.getReg(), TRI, true); AR.isValid(); ++AR) { + if (RegClass.contains(*AR)) { + O << EpiphanyInstPrinter::getRegisterName(*AR); + return false; + } + } + } + + return true; +} + +bool EpiphanyAsmPrinter::printSymbolicAddress(const MachineOperand &MO, + bool PrintImmediatePrefix, + StringRef Suffix, raw_ostream &O) { + StringRef Name; + StringRef Modifier; + switch (MO.getType()) { + default: + llvm_unreachable("Unexpected operand for symbolic address constraint"); + case MachineOperand::MO_GlobalAddress: + Name = Mang->getSymbol(MO.getGlobal())->getName(); + + // Global variables may be accessed either via a GOT or in various fun and + // interesting TLS-model specific ways. Set the prefix modifier as + // appropriate here. + if (const GlobalVariable *GV = dyn_cast(MO.getGlobal())) { + Reloc::Model RelocM = TM.getRelocationModel(); + if (Subtarget->GVIsIndirectSymbol(GV, RelocM)) { + Modifier = "got"; + } + } + break; + case MachineOperand::MO_BlockAddress: + Name = GetBlockAddressSymbol(MO.getBlockAddress())->getName(); + break; + case MachineOperand::MO_ExternalSymbol: + Name = MO.getSymbolName(); + break; + case MachineOperand::MO_ConstantPoolIndex: + Name = GetCPISymbol(MO.getIndex())->getName(); + break; + } + + // Some instructions (notably ADRP) don't take the # prefix for + // immediates. Only print it if asked to. + if (PrintImmediatePrefix) + O << '#'; + + // Only need the joining "_" if both the prefix and the suffix are + // non-null. This little block simply takes care of the four possibly + // combinations involved there. + if (Modifier == "" && Suffix == "") + O << Name; + else if (Modifier == "" && Suffix != "") + O << ":" << Suffix << ':' << Name; + else if (Modifier != "" && Suffix == "") + O << ":" << Modifier << ':' << Name; + else + O << ":" << Modifier << '_' << Suffix << ':' << Name; + + return false; +} + +bool EpiphanyAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, + const char *ExtraCode, raw_ostream &O) { + const TargetRegisterInfo *TRI = MF->getTarget().getRegisterInfo(); + if (!ExtraCode || !ExtraCode[0]) { + // There's actually no operand modifier, which leads to a slightly eclectic + // set of behaviour which we have to handle here. + const MachineOperand &MO = MI->getOperand(OpNum); + switch (MO.getType()) { + default: + llvm_unreachable("Unexpected operand for inline assembly"); + case MachineOperand::MO_Register: + // GCC prints the unmodified operand of a 'w' constraint as the vector + // register. Technically, we could allocate the argument as a VPR128, but + // that leads to extremely dodgy copies being generated to get the data + // there. + //if (printModifiedFPRAsmOperand(MO, TRI, Epiphany::VPR128RegClass, O)) + // O << EpiphanyInstPrinter::getRegisterName(MO.getReg()); + llvm_unreachable("oh fuck.. mo 128vpr"); + break; + case MachineOperand::MO_Immediate: + O << '#' << MO.getImm(); + break; + case MachineOperand::MO_FPImmediate: + assert(MO.getFPImm()->isExactlyValue(0.0) && "Only FP 0.0 expected"); + O << "#0.0"; + break; + case MachineOperand::MO_BlockAddress: + case MachineOperand::MO_ConstantPoolIndex: + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_ExternalSymbol: + return printSymbolicAddress(MO, false, "", O); + } + return false; + } + + // We have a real modifier to handle. + switch(ExtraCode[0]) { + default: + // See if this is a generic operand + return AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O); + case 'c': // Don't print "#" before an immediate operand. + if (!MI->getOperand(OpNum).isImm()) + return true; + O << MI->getOperand(OpNum).getImm(); + return false; + case 'w': + // Output 32-bit general register operand, constant zero as wzr, or stack + // pointer as wsp. Ignored when used with other operand types. + return printModifiedGPRAsmOperand(MI->getOperand(OpNum), TRI, + Epiphany::GPR32RegClass, O); + //case 'x': + // // Output 64-bit general register operand, constant zero as xzr, or stack + // // pointer as sp. Ignored when used with other operand types. + // return printModifiedGPRAsmOperand(MI->getOperand(OpNum), TRI, + // Epiphany::GPR64RegClass, O); + case 'H': + // Output higher numbered of a 64-bit general register pair + case 'Q': + // Output least significant register of a 64-bit general register pair + case 'R': + // Output most significant register of a 64-bit general register pair + + // FIXME note: these three operand modifiers will require, to some extent, + // adding a paired GPR64 register class. Initial investigation suggests that + // assertions are hit unless it has a type and is made legal for that type + // in ISelLowering. After that step is made, the number of modifications + // needed explodes (operation legality, calling conventions, stores, reg + // copies ...). + llvm_unreachable("FIXME: Unimplemented register pairs"); + //case 'b': + // // Output 8-bit FP/SIMD scalar register operand, prefixed with b. + // return printModifiedFPRAsmOperand(MI->getOperand(OpNum), TRI, + // Epiphany::FPR8RegClass, O); + //case 'h': + // // Output 16-bit FP/SIMD scalar register operand, prefixed with h. + // return printModifiedFPRAsmOperand(MI->getOperand(OpNum), TRI, + // Epiphany::FPR16RegClass, O); + case 's': + // Output 32-bit FP/SIMD scalar register operand, prefixed with s. + return printModifiedFPRAsmOperand(MI->getOperand(OpNum), TRI, + Epiphany::FPR32RegClass, O); + //case 'd': + // // Output 64-bit FP/SIMD scalar register operand, prefixed with d. + // return printModifiedFPRAsmOperand(MI->getOperand(OpNum), TRI, + // Epiphany::FPR64RegClass, O); + //case 'q': + // // Output 128-bit FP/SIMD scalar register operand, prefixed with q. + // return printModifiedFPRAsmOperand(MI->getOperand(OpNum), TRI, + // Epiphany::FPR128RegClass, O); + case 'A': + // Output symbolic address with appropriate relocation modifier (also + // suitable for ADRP). + return printSymbolicAddress(MI->getOperand(OpNum), false, "", O); + case 'L': + // Output bits 11:0 of symbolic address with appropriate :lo12: relocation + // modifier. + return printSymbolicAddress(MI->getOperand(OpNum), true, "lo12", O); + case 'G': + // Output bits 23:12 of symbolic address with appropriate :hi12: relocation + // modifier (currently only for TLS local exec). + return printSymbolicAddress(MI->getOperand(OpNum), true, "hi12", O); + } + + +} + +bool EpiphanyAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNum, + unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + // Currently both the memory constraints (m and Q) behave the same and amount + // to the address as a single register. In future, we may allow "m" to provide + // both a base and an offset. + const MachineOperand &MO = MI->getOperand(OpNum); + assert(MO.isReg() && "unexpected inline assembly memory operand"); + O << '[' << EpiphanyInstPrinter::getRegisterName(MO.getReg()) << ']'; + return false; +} + +void EpiphanyAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, + raw_ostream &OS) { + unsigned NOps = MI->getNumOperands(); + assert(NOps==4); + OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; + // cast away const; DIetc do not take const operands for some reason. + DIVariable V(const_cast(MI->getOperand(NOps-1).getMetadata())); + OS << V.getName(); + OS << " <- "; + // Frame address. Currently handles register +- offset only. + assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm()); + OS << '[' << EpiphanyInstPrinter::getRegisterName(MI->getOperand(0).getReg()); + OS << '+' << MI->getOperand(1).getImm(); + OS << ']'; + OS << "+" << MI->getOperand(NOps - 2).getImm(); +} + + +#include "EpiphanyGenMCPseudoLowering.inc" + +void EpiphanyAsmPrinter::EmitInstruction(const MachineInstr *MI) { + // Do any auto-generated pseudo lowerings. + if (emitPseudoExpansionLowering(OutStreamer, MI)) + return; + + switch (MI->getOpcode()) { + case Epiphany::DBG_VALUE: { + if (isVerbose() && OutStreamer.hasRawTextSupport()) { + SmallString<128> TmpStr; + raw_svector_ostream OS(TmpStr); + PrintDebugValueComment(MI, OS); + OutStreamer.EmitRawText(StringRef(OS.str())); + } + return; + } + } + + MCInst TmpInst; + LowerEpiphanyMachineInstrToMCInst(MI, TmpInst, *this); + OutStreamer.EmitInstruction(TmpInst); +} + +void EpiphanyAsmPrinter::EmitEndOfAsmFile(Module &M) { + if (Subtarget->isTargetELF()) { + const TargetLoweringObjectFileELF &TLOFELF = + static_cast(getObjFileLowering()); + + MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo(); + + // Output stubs for external and common global variables. + MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); + if (!Stubs.empty()) { + OutStreamer.SwitchSection(TLOFELF.getDataRelSection()); + const DataLayout *TD = TM.getDataLayout(); + + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + OutStreamer.EmitLabel(Stubs[i].first); + OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), + TD->getPointerSize(0), 0); + } + Stubs.clear(); + } + } +} + +bool EpiphanyAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + return AsmPrinter::runOnMachineFunction(MF); +} + +// Force static initialization. +extern "C" void LLVMInitializeEpiphanyAsmPrinter() { + RegisterAsmPrinter X(TheEpiphanyTarget); +} + diff --git a/EpiphanyAsmPrinter.h b/EpiphanyAsmPrinter.h new file mode 100644 index 0000000..07da42f --- /dev/null +++ b/EpiphanyAsmPrinter.h @@ -0,0 +1,80 @@ +// EpiphanyAsmPrinter.h - Print machine code to an Epiphany .s file -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Epiphany assembly printer class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EPIPHANYASMPRINTER_H +#define LLVM_EPIPHANYASMPRINTER_H + +#include "Epiphany.h" +#include "EpiphanyTargetMachine.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + +class MCOperand; + +class LLVM_LIBRARY_VISIBILITY EpiphanyAsmPrinter : public AsmPrinter { + + /// Subtarget - Keep a pointer to the EpiphanySubtarget around so that we can + /// make the right decision when printing asm code for different targets. + const EpiphanySubtarget *Subtarget; + + // emitPseudoExpansionLowering - tblgen'erated. + bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, + const MachineInstr *MI); + + public: + explicit EpiphanyAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer) { + Subtarget = &TM.getSubtarget(); + } + + bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const; + + MCOperand lowerSymbolOperand(const MachineOperand &MO, + const MCSymbol *Sym) const; + + void EmitInstruction(const MachineInstr *MI); + void EmitEndOfAsmFile(Module &M); + + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + + void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); + + /// printSymbolicAddress - Given some kind of reasonably bare symbolic + /// reference, print out the appropriate asm string to represent it. If + /// appropriate, a relocation-specifier will be produced, composed of a + /// general class derived from the MO parameter and an instruction-specific + /// suffix, provided in Suffix. E.g. ":got_lo12:" if a Suffix of "lo12" is + /// given. + bool printSymbolicAddress(const MachineOperand &MO, + bool PrintImmediatePrefix, + StringRef Suffix, raw_ostream &O); + + MachineLocation getDebugValueLocation(const MachineInstr *MI) const; + + virtual const char *getPassName() const { + return "Epiphany Assembly Printer"; + } + + virtual bool runOnMachineFunction(MachineFunction &MF); +}; +} // end namespace llvm + +#endif diff --git a/EpiphanyCallingConv.td b/EpiphanyCallingConv.td new file mode 100644 index 0000000..d47f61a --- /dev/null +++ b/EpiphanyCallingConv.td @@ -0,0 +1,25 @@ +//==-- EpiphanyCallingConv.td - Calling Conventions for ARM ----*- tblgen -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This describes the calling conventions for Epiphany architecture. +//===----------------------------------------------------------------------===// + +def CC_A64_APCS : CallingConv<[ + // Put ByVal arguments directly on the stack. + CCIfByVal>, + + //CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType> + // CCIfType<[f32], CCAssignToReg<[S0, S1, S2, S3, S4, S5, S6, S7]>>, + CCIfType<[i8, i16], CCPromoteToType>, + CCIfType<[i32,f32], CCAssignToReg<[R0, R1, R2, R3]>>, + // CCIfType<[i64,f64], CCAssignToReg<[D0, D1]>>, + CCIfType<[i32,f32], CCAssignToStack<4, 4>> + // CCIfType<[i64,f64], CCAssignToStack<8, 8>> +]>; + +def CSR_PCS : CalleeSavedRegs<(add LR, (sequence "R%u", 43, 32),(sequence "R%u", 11, 4))>; diff --git a/EpiphanyFrameLowering.cpp b/EpiphanyFrameLowering.cpp new file mode 100644 index 0000000..dfecad6 --- /dev/null +++ b/EpiphanyFrameLowering.cpp @@ -0,0 +1,563 @@ +//===- EpiphanyFrameLowering.cpp - Epiphany Frame Information ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Epiphany implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "Epiphany.h" +#include "EpiphanyFrameLowering.h" +#include "EpiphanyMachineFunctionInfo.h" +#include "EpiphanyInstrInfo.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/Function.h" +#include "llvm/MC/MachineLocation.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +void EpiphanyFrameLowering::splitSPAdjustments(uint64_t Total, + uint64_t &Initial, + uint64_t &Residual) const { + // 0x1f0 here is a pessimistic (i.e. realistic) boundary: x-register LDP + // instructions have a 7-bit signed immediate scaled by 8, giving a reach of + // 0x1f8, but stack adjustment should always be a multiple of 16. + if (Total <= 0x1f0) { + Initial = Total; + Residual = 0; + } else { + Initial = 0x1f0; + Residual = Total - Initial; + } +} + +void EpiphanyFrameLowering::emitPrologue(MachineFunction &MF) const { + EpiphanyMachineFunctionInfo *FuncInfo = + MF.getInfo(); + MachineBasicBlock &MBB = MF.front(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + MachineModuleInfo &MMI = MF.getMMI(); + std::vector &Moves = MMI.getFrameMoves(); + bool NeedsFrameMoves = MMI.hasDebugInfo() || MF.getFunction()->needsUnwindTableEntry(); + + uint64_t NumInitialBytes, NumResidualBytes; + + // Currently we expect the stack to be laid out by + // sub sp, sp, #initial + // stp R11, W30, [sp, #offset] + // ... + // str xxx, [sp, #offset] + // sub sp, sp, #rest (possibly via extra instructions). + if (MFI->getCalleeSavedInfo().size()) { + // If there are callee-saved registers, we want to store them efficiently as + // a block, and virtual base assignment happens too early to do it for us so + // we adjust the stack in two phases: first just for callee-saved fiddling, + // then to allocate the rest of the frame. + splitSPAdjustments(MFI->getStackSize(), NumInitialBytes, NumResidualBytes); + } else { + // If there aren't any callee-saved registers, two-phase adjustment is + // inefficient. It's more efficient to adjust with NumInitialBytes too + // because when we're in a "callee pops argument space" situation, that pop + // must be tacked onto Initial for correctness. + NumInitialBytes = MFI->getStackSize(); + NumResidualBytes = 0; + } + + // Tell everyone else how much adjustment we're expecting them to use. In + // particular if an adjustment is required for a tail call the epilogue could + // have a different view of things. + FuncInfo->setInitialStackAdjust(NumInitialBytes); + + EPIPHemitSPUpdate(MBB, MBBI, DL, TII, Epiphany::R63, -NumInitialBytes, + MachineInstr::FrameSetup); + + if (NeedsFrameMoves && NumInitialBytes) { + // We emit this update even if the CFA is set from a frame pointer later so + // that the CFA is valid in the interim. + MCSymbol *SPLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::PROLOG_LABEL)) + .addSym(SPLabel); + + MachineLocation Dst(MachineLocation::VirtualFP); + MachineLocation Src(Epiphany::SP, NumInitialBytes); + Moves.push_back(MachineMove(SPLabel, Dst, Src)); + } + + // Otherwise we need to set the frame pointer and/or add a second stack + // adjustment. + + bool FPNeedsSetting = hasFP(MF); + for (; MBBI != MBB.end(); ++MBBI) { + // Note that this search makes strong assumptions about the operation used + // to store the frame-pointer: it must be "STP R11, W30, ...". This could + // change in future, but until then there's no point in implementing + // untestable more generic cases. + //if (FPNeedsSetting && MBBI->getOpcode() == Epiphany::LSPair64_STR <------------------------ we don't have a pair instruction :( + // && MBBI->getOperand(0).getReg() == Epiphany::R11) { + // int64_t R11FrameIdx = MBBI->getOperand(2).getIndex(); + // FuncInfo->setFramePointerOffset(MFI->getObjectOffset(R11FrameIdx)); + + // ++MBBI; + // EPIPHemitRegUpdate(MBB, MBBI, DL, TII, Epiphany::R11, Epiphany::SP, + // Epiphany::R11, + // NumInitialBytes + MFI->getObjectOffset(R11FrameIdx), + // MachineInstr::FrameSetup); + + // // The offset adjustment used when emitting debugging locations relative + // // to whatever frame base is set. Epiphany uses the default frame base (FP + // // or SP) and this adjusts the calculations to be correct. + // MFI->setOffsetAdjustment(- MFI->getObjectOffset(R11FrameIdx) + // - MFI->getStackSize()); + + // if (NeedsFrameMoves) { + // MCSymbol *FPLabel = MMI.getContext().CreateTempSymbol(); + // BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::PROLOG_LABEL)) + // .addSym(FPLabel); + // MachineLocation Dst(MachineLocation::VirtualFP); + // MachineLocation Src(Epiphany::R11, -MFI->getObjectOffset(R11FrameIdx)); + // Moves.push_back(MachineMove(FPLabel, Dst, Src)); + // } + + // FPNeedsSetting = false; + //} + + if (!MBBI->getFlag(MachineInstr::FrameSetup)) + break; + } + + assert(!FPNeedsSetting && "Frame pointer couldn't be set"); + + EPIPHemitSPUpdate(MBB, MBBI, DL, TII, Epiphany::R63, -NumResidualBytes, + MachineInstr::FrameSetup); + + // Now we emit the rest of the frame setup information, if necessary: we've + // already noted the FP and initial SP moves so we're left with the prologue's + // final SP update and callee-saved register locations. + if (!NeedsFrameMoves) + return; + + // Reuse the label if appropriate, so create it in this outer scope. + MCSymbol *CSLabel = 0; + + // The rest of the stack adjustment + if (!hasFP(MF) && NumResidualBytes) { + CSLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::PROLOG_LABEL)) + .addSym(CSLabel); + + MachineLocation Dst(MachineLocation::VirtualFP); + MachineLocation Src(Epiphany::SP, NumResidualBytes + NumInitialBytes); + Moves.push_back(MachineMove(CSLabel, Dst, Src)); + } + + // And any callee-saved registers (it's fine to leave them to the end here, + // because the old values are still valid at this point. + const std::vector &CSI = MFI->getCalleeSavedInfo(); + if (CSI.size()) { + if (!CSLabel) { + CSLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::PROLOG_LABEL)) + .addSym(CSLabel); + } + + for (std::vector::const_iterator I = CSI.begin(), + E = CSI.end(); I != E; ++I) { + MachineLocation Dst(MachineLocation::VirtualFP, + MFI->getObjectOffset(I->getFrameIdx())); + MachineLocation Src(I->getReg()); + Moves.push_back(MachineMove(CSLabel, Dst, Src)); + } + } +} + +void +EpiphanyFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + EpiphanyMachineFunctionInfo *FuncInfo = + MF.getInfo(); + + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + DebugLoc DL = MBBI->getDebugLoc(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + unsigned RetOpcode = MBBI->getOpcode(); + + // Initial and residual are named for consitency with the prologue. Note that + // in the epilogue, the residual adjustment is executed first. + uint64_t NumInitialBytes = FuncInfo->getInitialStackAdjust(); + uint64_t NumResidualBytes = MFI.getStackSize() - NumInitialBytes; + uint64_t ArgumentPopSize = 0; + + ArgumentPopSize = FuncInfo->getArgumentStackToRestore(); + + assert(NumInitialBytes % 8 == 0 && NumResidualBytes % 8 == 0 + && "refusing to adjust stack by misaligned amt"); + + // We may need to address callee-saved registers differently, so find out the + // bound on the frame indices. + const std::vector &CSI = MFI.getCalleeSavedInfo(); + int MinCSFI = 0; + int MaxCSFI = -1; + + if (CSI.size()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); + } + + // The "residual" stack update comes first from this direction and guarantees + // that SP is NumInitialBytes below its value on function entry, either by a + // direct update or restoring it from the frame pointer. + if (NumInitialBytes + ArgumentPopSize != 0) { + EPIPHemitSPUpdate(MBB, MBBI, DL, TII, Epiphany::R63, + NumInitialBytes + ArgumentPopSize); + --MBBI; + } + + + // MBBI now points to the instruction just past the last callee-saved + // restoration (either RET/B if NumInitialBytes == 0, or the "ADD sp, sp" + // otherwise). + + // Now we need to find out where to put the bulk of the stack adjustment + MachineBasicBlock::iterator FirstEpilogue = MBBI; + while (MBBI != MBB.begin()) { + --MBBI; + + unsigned FrameOp; + for (FrameOp = 0; FrameOp < MBBI->getNumOperands(); ++FrameOp) { + if (MBBI->getOperand(FrameOp).isFI()) + break; + } + + // If this instruction doesn't have a frame index we've reached the end of + // the callee-save restoration. + if (FrameOp == MBBI->getNumOperands()) + break; + + // Likewise if it *is* a local reference, but not to a callee-saved object. + int FrameIdx = MBBI->getOperand(FrameOp).getIndex(); + if (FrameIdx < MinCSFI || FrameIdx > MaxCSFI) + break; + + FirstEpilogue = MBBI; + } + + if (MF.getFrameInfo()->hasVarSizedObjects()) { + int64_t StaticFrameBase; + StaticFrameBase = -(NumInitialBytes + FuncInfo->getFramePointerOffset()); + EPIPHemitRegUpdate(MBB, FirstEpilogue, DL, TII, + Epiphany::SP, Epiphany::R11, Epiphany::NoRegister, + StaticFrameBase); + } else { + EPIPHemitSPUpdate(MBB, FirstEpilogue, DL,TII, Epiphany::R63, NumResidualBytes); + } +} + +int64_t +EpiphanyFrameLowering::resolveFrameIndexReference(MachineFunction &MF, + int FrameIndex, + unsigned &FrameReg, + int SPAdj, + bool IsCalleeSaveOp) const { + EpiphanyMachineFunctionInfo *FuncInfo = + MF.getInfo(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + + int64_t TopOfFrameOffset = MFI->getObjectOffset(FrameIndex); + + assert(!(IsCalleeSaveOp && FuncInfo->getInitialStackAdjust() == 0) + && "callee-saved register in unexpected place"); + + // If the frame for this function is particularly large, we adjust the stack + // in two phases which means the callee-save related operations see a + // different (intermediate) stack size. + int64_t FrameRegPos; + if (IsCalleeSaveOp) { + FrameReg = Epiphany::SP; + FrameRegPos = -static_cast(FuncInfo->getInitialStackAdjust()); + } else if (useFPForAddressing(MF)) { + // Have to use the frame pointer since we have no idea where SP is. + FrameReg = Epiphany::R11; + FrameRegPos = FuncInfo->getFramePointerOffset(); + } else { + FrameReg = Epiphany::SP; + FrameRegPos = -static_cast(MFI->getStackSize()) + SPAdj; + } + + return TopOfFrameOffset - FrameRegPos; +} + +void +EpiphanyFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const { + const EpiphanyRegisterInfo *RegInfo = static_cast(MF.getTarget().getRegisterInfo()); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const EpiphanyInstrInfo &TII = *static_cast(MF.getTarget().getInstrInfo()); + + if (hasFP(MF)) { + MF.getRegInfo().setPhysRegUsed(Epiphany::R11); + MF.getRegInfo().setPhysRegUsed(Epiphany::LR); + } + + // If addressing of local variables is going to be more complicated than + // shoving a base register and an offset into the instruction then we may well + // need to scavenge registers. We should either specifically add an + // callee-save register for this purpose or allocate an extra spill slot. + + bool BigStack = + (RS && MFI->estimateStackSize(MF) >= TII.estimateRSStackLimit(MF)) + || MFI->hasVarSizedObjects() // Access will be from R11: messes things up + || (MFI->adjustsStack() && !hasReservedCallFrame(MF)); + + if (!BigStack) + return; + + // We certainly need some slack space for the scavenger, preferably an extra + // register. + const uint16_t *CSRegs = RegInfo->getCalleeSavedRegs(); + uint16_t ExtraReg = Epiphany::NoRegister; + + for (unsigned i = 0; CSRegs[i]; ++i) { + if (Epiphany::GPR32RegClass.contains(CSRegs[i]) && !MF.getRegInfo().isPhysRegUsed(CSRegs[i])) { + ExtraReg = CSRegs[i]; + break; + } + } + + if (ExtraReg != 0) { + MF.getRegInfo().setPhysRegUsed(ExtraReg); + } else { + // Create a stack slot for scavenging purposes. PrologEpilogInserter + // helpfully places it near either SP or FP for us to avoid + // infinitely-regression during scavenging. + const TargetRegisterClass *RC = &Epiphany::GPR32RegClass; + RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(), + RC->getAlignment(), + false)); + } +} + +bool EpiphanyFrameLowering::determinePrologueDeath(MachineBasicBlock &MBB, + unsigned Reg) const { + // If @llvm.returnaddress is called then it will refer to W30 by some means; + // the prologue store does not kill the register. + if (Reg == Epiphany::LR) { + if (MBB.getParent()->getFrameInfo()->isReturnAddressTaken() + && MBB.getParent()->getRegInfo().isLiveIn(Reg)) + return false; + } + + // In all other cases, physical registers are dead after they've been saved + // but live at the beginning of the prologue block. + MBB.addLiveIn(Reg); + return true; +} + +void +EpiphanyFrameLowering::eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const { + const EpiphanyInstrInfo &TII = *static_cast(MF.getTarget().getInstrInfo()); + DebugLoc dl = MI->getDebugLoc(); + int Opcode = MI->getOpcode(); + bool IsDestroy = Opcode == TII.getCallFrameDestroyOpcode(); + uint64_t CalleePopAmount = IsDestroy ? MI->getOperand(1).getImm() : 0; + + if (!hasReservedCallFrame(MF)) { + unsigned Align = getStackAlignment(); + + int64_t Amount = MI->getOperand(0).getImm(); + Amount = RoundUpToAlignment(Amount, Align); + if (!IsDestroy) Amount = -Amount; + + // N.b. if CalleePopAmount is valid but zero (i.e. callee would pop, but it + // doesn't have to pop anything), then the first operand will be zero too so + // this adjustment is a no-op. + if (CalleePopAmount == 0) { + // FIXME: in-function stack adjustment for calls is limited to 12-bits + // because there's no guaranteed temporary register available. Mostly call + // frames will be allocated at the start of a function so this is OK, but + // it is a limitation that needs dealing with. + assert(Amount > -(0x3FF) && Amount < 0x3FF && "call frame too large"); + EPIPHemitSPUpdate(MBB, MI, dl, TII, Epiphany::NoRegister, Amount); + } + } else if (CalleePopAmount != 0) { + // If the calling convention demands that the callee pops arguments from the + // stack, we want to add it back if we have a reserved call frame. + assert(CalleePopAmount < 0x3FF && "call frame too large"); + EPIPHemitSPUpdate(MBB, MI, dl, TII, Epiphany::NoRegister, -CalleePopAmount); + } + + MBB.erase(MI); +} + +void +EpiphanyFrameLowering::emitFrameMemOps(bool isPrologue, MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const { + DebugLoc DL = MBB.findDebugLoc(MBBI); + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + + // A certain amount of implicit contract is present here. The actual stack + // offsets haven't been allocated officially yet, so for strictly correct code + // we rely on the fact that the elements of CSI are allocated in order + // starting at SP, purely as dictated by size and alignment. In practice since + // this function handles the only accesses to those slots it's not quite so + // important. + // + // We have also ordered the Callee-saved register list in EpiphanyCallingConv + // so that the above scheme puts registers in order: in particular we want + // &W30 to be &R11+8 for an ABI-correct frame record (PCS 5.2.2) + for (unsigned i = 0, e = CSI.size(); i < e; ++i) { + unsigned Reg = CSI[i].getReg(); + + // Let's try a double store first: regs must be a even-odd pair + MachineInstrBuilder NewMI; + bool Pair = false; + + // alignment? + //unsigned suba, subb, sra=0, srb=0; + //if(i+1 < CSI.size()){ + // suba = CSI[i].getReg(); + // subb = CSI[i+1].getReg(); + // sra = TRI->getMatchingSuperReg (suba, Epiphany::sub_even, &Epiphany::DPR64RegClass); + // srb = TRI->getMatchingSuperReg (subb, Epiphany::sub_odd, &Epiphany::DPR64RegClass); + // if( (!sra || !srb) || sra != srb){ + // srb = TRI->getMatchingSuperReg (suba, Epiphany::sub_odd, &Epiphany::DPR64RegClass); + // sra = TRI->getMatchingSuperReg (subb, Epiphany::sub_even, &Epiphany::DPR64RegClass); + // std::swap(suba,subb); + // } + //} + //if ((sra && srb) && sra == srb) { + // Pair = true; + // unsigned StLow = 0, StHigh = 0; + // if (isPrologue) { + // // Most of these registers will be live-in to the MBB and killed by our + // // store, though there are exceptions (see determinePrologueDeath). + // StLow = getKillRegState(determinePrologueDeath(MBB, CSI[i+1].getReg())); + // StHigh = getKillRegState(determinePrologueDeath(MBB, CSI[i].getReg())); + // } else { + // StLow = RegState::Define; + // StHigh = RegState::Define; + // } + + // //HACK FIXME liveness is a bit wrong... + // NewMI = BuildMI(MBB, MBBI, DL, TII.get(isPrologue ? Epiphany::LSFP64_STR : Epiphany::LSFP64_LDR)) + // .addReg(sra, RegState::Kill); + // //.addReg(suba, StLow) + // //.addReg(subb, StHigh | RegState::Implicit); + + // // If it's a paired op, we've consumed two registers + // ++i; + //} + //else { + unsigned State; + if (isPrologue) { + State = getKillRegState(determinePrologueDeath(MBB, CSI[i].getReg())); + } else { + State = RegState::Define; + } + + NewMI = BuildMI(MBB, MBBI, DL, TII.get(isPrologue ? Epiphany::LS32_STR : Epiphany::LS32_LDR)) + .addReg(CSI[i].getReg(), State); + //} + + // Are we grabbing the right index? FIXME + int FrameIdx = CSI[Pair ? i-1 : i].getFrameIdx(); + + MachineMemOperand *MMO = MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(FrameIdx), + isPrologue ? MachineMemOperand::MOStore : MachineMemOperand::MOLoad, + Pair ? 8 : 4, + MFI.getObjectAlignment(FrameIdx)); + + NewMI.addFrameIndex(FrameIdx).addImm(0)/*address-register offset*/.addMemOperand(MMO); + + if (isPrologue) + NewMI.setMIFlags(MachineInstr::FrameSetup); + + // For aesthetic reasons, during an epilogue we want to emit complementary + // operations to the prologue, but in the opposite order. So we still + // iterate through the CalleeSavedInfo list in order, but we put the + // instructions successively earlier in the MBB. + if (!isPrologue) + --MBBI; + } +} + +bool +EpiphanyFrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return false; + emitFrameMemOps(/* isPrologue = */ true, MBB, MBBI, CSI, TRI); + + return true; +} + +bool +EpiphanyFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const { + + if (CSI.empty()) + return false; + emitFrameMemOps(/* isPrologue = */ false, MBB, MBBI, CSI, TRI); + + return true; +} + +bool +EpiphanyFrameLowering::hasFP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetRegisterInfo *RI = MF.getTarget().getRegisterInfo(); + + // This is a decision of ABI compliance. The Epiphany PCS gives various options + // for conformance, and even at the most stringent level more or less permits + // elimination for leaf functions because there's no loss of functionality + // (for debugging etc).. + if (MF.getTarget().Options.DisableFramePointerElim(MF) && MFI->hasCalls()) + return true; + + // The following are hard-limits: incorrect code will be generated if we try + // to omit the frame. + return (RI->needsStackRealignment(MF) || + MFI->hasVarSizedObjects() || + MFI->isFrameAddressTaken()); +} + +bool +EpiphanyFrameLowering::useFPForAddressing(const MachineFunction &MF) const { + return MF.getFrameInfo()->hasVarSizedObjects(); +} + +bool +EpiphanyFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + + // Of the various reasons for having a frame pointer, it's actually only + // variable-sized objects that prevent reservation of a call frame. + return !(hasFP(MF) && MFI->hasVarSizedObjects()); +} diff --git a/EpiphanyFrameLowering.h b/EpiphanyFrameLowering.h new file mode 100644 index 0000000..e705c9d --- /dev/null +++ b/EpiphanyFrameLowering.h @@ -0,0 +1,106 @@ +//==- EpiphanyFrameLowering.h - Define frame lowering for Epiphany -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class implements the Epiphany-specific parts of the TargetFrameLowering +// class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EPIPHANY_FRAMEINFO_H +#define LLVM_EPIPHANY_FRAMEINFO_H + +#include "EpiphanySubtarget.h" +#include "llvm/Target/TargetFrameLowering.h" + +namespace llvm { +class EpiphanySubtarget; + +class EpiphanyFrameLowering : public TargetFrameLowering { +private: + // In order to unify the spilling and restoring of callee-saved registers into + // emitFrameMemOps, we need to be able to specify which instructions to use + // for the relevant memory operations on each register class. An array of the + // following struct is populated and passed in to achieve this. + struct LoadStoreMethod { + const TargetRegisterClass *RegClass; // E.g. GPR64RegClass + + // The preferred instruction. + unsigned PairOpcode; // E.g. LSPair64_STR + + // Sometimes only a single register can be handled at once. + unsigned SingleOpcode; // E.g. LS64_STR + }; +protected: + const EpiphanySubtarget &STI; + +public: + explicit EpiphanyFrameLowering(const EpiphanySubtarget &sti) + : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 8, 0, 4), + STI(sti) { + } + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + virtual void emitPrologue(MachineFunction &MF) const; + virtual void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + /// Decides how much stack adjustment to perform in each phase of the prologue + /// and epilogue. + void splitSPAdjustments(uint64_t Total, uint64_t &Initial, + uint64_t &Residual) const; + + int64_t resolveFrameIndexReference(MachineFunction &MF, int FrameIndex, + unsigned &FrameReg, int SPAdj, + bool IsCalleeSaveOp) const; + + virtual void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const; + + virtual bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const; + virtual bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const; + + /// If the register is X30 (i.e. LR) and the return address is used in the + /// function then the callee-save store doesn't actually kill the register, + /// otherwise it does. + bool determinePrologueDeath(MachineBasicBlock &MBB, unsigned Reg) const; + + /// This function emits the loads or stores required during prologue and + /// epilogue as efficiently as possible. + /// + /// The operations involved in setting up and tearing down the frame are + /// similar enough to warrant a shared function, particularly as discrepancies + /// between the two would be disastrous. + void emitFrameMemOps(bool isStore, MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const; + + + virtual bool hasFP(const MachineFunction &MF) const; + + virtual bool useFPForAddressing(const MachineFunction &MF) const; + + /// On AA + virtual bool hasReservedCallFrame(const MachineFunction &MF) const; + +}; + +} // End llvm namespace + +#endif diff --git a/EpiphanyISelDAGToDAG.cpp b/EpiphanyISelDAGToDAG.cpp new file mode 100644 index 0000000..0f8d1f8 --- /dev/null +++ b/EpiphanyISelDAGToDAG.cpp @@ -0,0 +1,266 @@ +//===-- EpiphanyISelDAGToDAG.cpp - A dag to dag inst selector for Epiphany --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the Epiphany target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "epiphany-isel" +#include "Epiphany.h" +#include "EpiphanyInstrInfo.h" +#include "EpiphanySubtarget.h" +#include "EpiphanyTargetMachine.h" +#include "Utils/EpiphanyBaseInfo.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +//===--------------------------------------------------------------------===// +/// Epiphany specific code to select Epiphany machine instructions for +/// SelectionDAG operations. +/// +namespace { + +class EpiphanyDAGToDAGISel : public SelectionDAGISel { + EpiphanyTargetMachine &TM; + const EpiphanyInstrInfo *TII; + + /// Keep a pointer to the EpiphanySubtarget around so that we can + /// make the right decision when generating code for different targets. + const EpiphanySubtarget *Subtarget; + +public: + explicit EpiphanyDAGToDAGISel(EpiphanyTargetMachine &tm, + CodeGenOpt::Level OptLevel) + : SelectionDAGISel(tm, OptLevel), TM(tm), + TII(static_cast(TM.getInstrInfo())), + Subtarget(&TM.getSubtarget()) { + } + + virtual const char *getPassName() const { + return "Epiphany Instruction Selection"; + } + + // Include the pieces autogenerated from the target description. +#include "EpiphanyGenDAGISel.inc" + + // getImm - Return a target constant with the specified value. + inline SDValue getImm(const SDNode *Node, unsigned Imm) { + return CurDAG->getTargetConstant(Imm, Node->getValueType(0)); + } + + template + bool SelectOffsetUImm11(SDValue N, SDValue &UImm12) { + const ConstantSDNode *CN = dyn_cast(N); + const int maxv = ((2<<10)-1); // = 2^11-1 -> 11 bit + if (!CN || CN->getSExtValue() % MemSize != 0 || !(CN->getSExtValue() / MemSize >= -maxv && CN->getSExtValue() / MemSize <= maxv)) + return false; + + UImm12 = CurDAG->getTargetConstant(CN->getSExtValue() / MemSize, MVT::i32); + return true; + } + + SDNode *TrySelectToMoveImm(SDNode *N); + SDNode *LowerToFPLitPool(SDNode *Node); + SDNode *SelectToLitPool(SDNode *N); + + SDNode* Select(SDNode*); +private: +}; +} + +SDNode *EpiphanyDAGToDAGISel::TrySelectToMoveImm(SDNode *Node) { + SDNode *ResNode; + DebugLoc dl = Node->getDebugLoc(); + EVT DestType = Node->getValueType(0); + unsigned DestWidth = DestType.getSizeInBits(); + + if (DestWidth != 32) + llvm_unreachable("move to dst !=32 ?!"); + + if(DestType.isInteger()){ + uint64_t BitPat = cast(Node)->getZExtValue(); + if (BitPat & ~0xffffffffULL){ + llvm_unreachable("wat."); + } + + // 0 or 16 lower bits + ResNode = CurDAG->getMachineNode(Epiphany::MOVri, dl, DestType, CurDAG->getTargetConstant(BitPat, MVT::i32)); + + if (BitPat & 0xffff0000ULL){// 16 upper bits + //this is LUi(LLi(val{15-0}), val{31-16}) + ResNode = CurDAG->getMachineNode(Epiphany::MOVTri, dl, DestType, SDValue(ResNode, 0), CurDAG->getTargetConstant(BitPat, MVT::i32)); + } + } else if(DestType.isFloatingPoint()){ + APFloat BitPat = cast(Node)->getValueAPF(); + + ResNode = CurDAG->getMachineNode(Epiphany::MOVri_nopat_f, dl, DestType, CurDAG->getTargetConstantFP(BitPat, MVT::f32)); + //this is LUi(LLi(val{15-0}), val{31-16}) + if(!BitPat.isPosZero()) + ResNode = CurDAG->getMachineNode(Epiphany::MOVTri_nopat_f, dl, DestType, SDValue(ResNode, 0), CurDAG->getTargetConstantFP(BitPat, MVT::f32)); + + } + + ReplaceUses(Node, ResNode); + return ResNode; +} + +SDNode *EpiphanyDAGToDAGISel::SelectToLitPool(SDNode *Node) { + DebugLoc DL = Node->getDebugLoc(); + uint64_t UnsignedVal = cast(Node)->getZExtValue(); + int64_t SignedVal = cast(Node)->getSExtValue(); + EVT DestType = Node->getValueType(0); + EVT PtrVT = TLI.getPointerTy(); + + // Since we may end up loading a 64-bit constant from a 32-bit entry the + // constant in the pool may have a different type to the eventual node. + ISD::LoadExtType Extension; + EVT MemType; + + assert((DestType == MVT::i64 || DestType == MVT::i32) + && "Only expect integer constants at the moment"); + + if (DestType == MVT::i32) { + Extension = ISD::NON_EXTLOAD; + MemType = MVT::i32; + } else if (UnsignedVal <= UINT32_MAX) { + Extension = ISD::ZEXTLOAD; + MemType = MVT::i32; + } else if (SignedVal >= INT32_MIN && SignedVal <= INT32_MAX) { + Extension = ISD::SEXTLOAD; + MemType = MVT::i32; + } else { + Extension = ISD::NON_EXTLOAD; + MemType = MVT::i32; + } + + Constant *CV = ConstantInt::get(Type::getIntNTy(*CurDAG->getContext(), + MemType.getSizeInBits()), + UnsignedVal); + SDValue PoolAddr; + unsigned Alignment = TLI.getDataLayout()->getABITypeAlignment(CV->getType()); + PoolAddr = CurDAG->getNode(EpiphanyISD::WrapperSmall, DL, PtrVT, + CurDAG->getTargetConstantPool(CV, PtrVT, 0, 0, + EpiphanyII::MO_HI16), + CurDAG->getTargetConstantPool(CV, PtrVT, 0, 0, + EpiphanyII::MO_LO16), + CurDAG->getConstant(Alignment, MVT::i32)); + + return CurDAG->getExtLoad(Extension, DL, DestType, CurDAG->getEntryNode(), + PoolAddr, + MachinePointerInfo::getConstantPool(), MemType, + /* isVolatile = */ false, + /* isNonTemporal = */ false, + Alignment).getNode(); +} + +SDNode *EpiphanyDAGToDAGISel::LowerToFPLitPool(SDNode *Node) { + DebugLoc DL = Node->getDebugLoc(); + const ConstantFP *FV = cast(Node)->getConstantFPValue(); + EVT PtrVT = TLI.getPointerTy(); + EVT DestType = Node->getValueType(0); + + unsigned Alignment = TLI.getDataLayout()->getABITypeAlignment(FV->getType()); + SDValue PoolAddr; + + assert(TM.getCodeModel() == CodeModel::Small && + "Only small code model supported"); + PoolAddr = CurDAG->getNode(EpiphanyISD::WrapperSmall, DL, PtrVT, + CurDAG->getTargetConstantPool(FV, PtrVT, 0, 0, + EpiphanyII::MO_HI16), + CurDAG->getTargetConstantPool(FV, PtrVT, 0, 0, + EpiphanyII::MO_LO16), + CurDAG->getConstant(Alignment, MVT::i32)); + + return CurDAG->getLoad(DestType, DL, CurDAG->getEntryNode(), PoolAddr, + MachinePointerInfo::getConstantPool(), + /* isVolatile = */ false, + /* isNonTemporal = */ false, + /* isInvariant = */ true, + Alignment).getNode(); +} + +SDNode *EpiphanyDAGToDAGISel::Select(SDNode *Node) { + // Dump information about the Node being selected + DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << "\n"); + + if (Node->isMachineOpcode()) { + DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); + return NULL; + } + + switch (Node->getOpcode()) { + case ISD::FrameIndex: { + int FI = cast(Node)->getIndex(); + EVT PtrTy = TLI.getPointerTy(); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, PtrTy); + return CurDAG->SelectNodeTo(Node, Epiphany::ADDri, PtrTy, + TFI, CurDAG->getTargetConstant(0, PtrTy)); + } + case ISD::ConstantPool: { + // Constant pools are fine, just create a Target entry. + ConstantPoolSDNode *CN = cast(Node); + const Constant *C = CN->getConstVal(); + SDValue CP = CurDAG->getTargetConstantPool(C, CN->getValueType(0)); + + ReplaceUses(SDValue(Node, 0), CP); + return NULL; + } + case ISD::Constant: { + SDNode *ResNode = 0; + ResNode = TrySelectToMoveImm(Node); + if (ResNode) + return ResNode; + + llvm_unreachable("contant fail."); + //ResNode = SelectToLitPool(Node); + //assert(ResNode && "We need *some* way to materialise a constant"); + + //// We want to continue selection at this point since the litpool access + //// generated used generic nodes for simplicity. + //ReplaceUses(SDValue(Node, 0), SDValue(ResNode, 0)); + //Node = ResNode; + //break; + } + case ISD::ConstantFP: { + //SDNode *ResNode = LowerToFPLitPool(Node); + //ReplaceUses(SDValue(Node, 0), SDValue(ResNode, 0)); + + //// We want to continue selection at this point since the litpool access + //// generated used generic nodes for simplicity. + //Node = ResNode; + //break; + return TrySelectToMoveImm(Node); + } + default: + break; // Let generic code handle it + } + + SDNode *ResNode = SelectCode(Node); + + DEBUG(dbgs() << "=> "; + if (ResNode == NULL || ResNode == Node) + Node->dump(CurDAG); + else + ResNode->dump(CurDAG); + dbgs() << "\n"); + + return ResNode; +} + +/// This pass converts a legalized DAG into a Epiphany-specific DAG, ready for +/// instruction scheduling. +FunctionPass *llvm::createEpiphanyISelDAG(EpiphanyTargetMachine &TM, + CodeGenOpt::Level OptLevel) { + return new EpiphanyDAGToDAGISel(TM, OptLevel); +} diff --git a/EpiphanyISelLowering.cpp b/EpiphanyISelLowering.cpp new file mode 100644 index 0000000..2d365e0 --- /dev/null +++ b/EpiphanyISelLowering.cpp @@ -0,0 +1,1074 @@ +//===-- EpiphanyISelLowering.cpp - Epiphany DAG Lowering Implementation -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that Epiphany uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "epiphany-isel" +#include "Epiphany.h" +#include "EpiphanyISelLowering.h" +#include "EpiphanyMachineFunctionInfo.h" +#include "EpiphanyTargetMachine.h" +#include "EpiphanyTargetObjectFile.h" +#include "Utils/EpiphanyBaseInfo.h" +#include "llvm/CodeGen/Analysis.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/IR/CallingConv.h" + +using namespace llvm; + +static TargetLoweringObjectFile *createTLOF(EpiphanyTargetMachine &TM) { + const EpiphanySubtarget *Subtarget = &TM.getSubtarget(); + + return new EpiphanyLinuxTargetObjectFile(); +} + + +EpiphanyTargetLowering::EpiphanyTargetLowering(EpiphanyTargetMachine &TM) + : TargetLowering(TM, createTLOF(TM)), + Subtarget(&TM.getSubtarget()), + RegInfo(TM.getRegisterInfo()), + Itins(TM.getInstrItineraryData()) { + + // Scalar register <-> type mapping + addRegisterClass(MVT::i32, &Epiphany::GPR32RegClass); + addRegisterClass(MVT::f32, &Epiphany::FPR32RegClass); + + // we do have a reg class, but the only supported operations are loads and stores + //addRegisterClass(MVT::i64, &Epiphany::DPR64RegClass); + //addRegisterClass(MVT::f64, &Epiphany::DPR64RegClass); + + computeRegisterProperties(); + + setTargetDAGCombine(ISD::FADD); + setTargetDAGCombine(ISD::FSUB); + + // Epiphany does not have i1 loads, or much of anything for i1 really. + setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); + + setStackPointerRegisterToSaveRestore(Epiphany::SP); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + + // We'll lower globals to wrappers for selection. + setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); + + // A64 instructions have the comparison predicate attached to the user of the + // result, but having a separate comparison is valuable for matching. + setOperationAction(ISD::BR_CC, MVT::i32, Custom); + setOperationAction(ISD::BR_CC, MVT::f32, Custom); + setOperationAction(ISD::SELECT, MVT::i32, Custom); + setOperationAction(ISD::SELECT, MVT::f32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); + setOperationAction(ISD::BRCOND, MVT::Other, Custom); + setOperationAction(ISD::SETCC, MVT::i32, Custom); + setOperationAction(ISD::SETCC, MVT::f32, Custom); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::JumpTable, MVT::i32, Custom); + setOperationAction(ISD::VASTART, MVT::Other, Expand); + setOperationAction(ISD::VACOPY, MVT::Other, Expand); + setOperationAction(ISD::VAEND, MVT::Other, Expand); + setOperationAction(ISD::VAARG, MVT::Other, Expand); + setOperationAction(ISD::BlockAddress, MVT::i32, Custom); + setOperationAction(ISD::ROTL, MVT::i32, Expand); + setOperationAction(ISD::UREM, MVT::i32, Expand); + setOperationAction(ISD::UDIVREM, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::SDIVREM, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i32, Expand); + setOperationAction(ISD::UDIV, MVT::i32, Expand); + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + + setOperationAction(ISD::FNEG, MVT::f32, Custom); + + // Legal floating-point operations. + setOperationAction(ISD::FMUL, MVT::f32, Legal); + setOperationAction(ISD::FADD, MVT::f32, Legal); + setOperationAction(ISD::FSUB, MVT::f32, Legal); + + + setOperationAction(ISD::FABS, MVT::f32, Legal); + setOperationAction(ISD::ConstantFP, MVT::f32, Legal); + + //setOperationAction(ISD::FMA, MVT::f32, Expand); custom combine due to fneg, we have fmsub + + // Illegal floating-point operations. + setOperationAction(ISD::FDIV, MVT::f32, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); + setOperationAction(ISD::FCOS, MVT::f32, Expand); + setOperationAction(ISD::FEXP, MVT::f32, Expand); + setOperationAction(ISD::FEXP2, MVT::f32, Expand); + setOperationAction(ISD::FLOG, MVT::f32, Expand); + setOperationAction(ISD::FLOG2, MVT::f32, Expand); + setOperationAction(ISD::FLOG10, MVT::f32, Expand); + setOperationAction(ISD::FPOW, MVT::f32, Expand); + setOperationAction(ISD::FPOWI, MVT::f32, Expand); + setOperationAction(ISD::FREM, MVT::f32, Expand); + setOperationAction(ISD::FSIN, MVT::f32, Expand); + + +//fix/float + setOperationAction(ISD::FP_TO_SINT, MVT::i32, Legal); + setOperationAction(ISD::SINT_TO_FP, MVT::i32, Legal); + + } + +EVT EpiphanyTargetLowering::getSetCCResultType(EVT VT) const { + // It's reasonably important that this value matches the "natural" legal + // promotion from i1 for scalar types. Otherwise LegalizeTypes can get itself + // in a twist (e.g. inserting an any_extend which then becomes i32 -> i32). + if (!VT.isVector()) return MVT::i32; + return VT.changeVectorElementTypeToInteger(); +} + +MachineBasicBlock * +EpiphanyTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const { + switch (MI->getOpcode()) { + default: llvm_unreachable("Unhandled instruction with custom inserter"); + //case Epiphany::F128CSEL: + // return EmitF128CSEL(MI, MBB); + } +} + + +const char *EpiphanyTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + case EpiphanyISD::BR_CC: return "EpiphanyISD::BR_CC"; + case EpiphanyISD::Call: return "EpiphanyISD::Call"; + case EpiphanyISD::Ret: return "EpiphanyISD::Ret"; + case EpiphanyISD::SELECT_CC: return "EpiphanyISD::SELECT_CC"; + case EpiphanyISD::SETCC: return "EpiphanyISD::SETCC"; + case EpiphanyISD::WrapperSmall: return "EpiphanyISD::WrapperSmall"; + case EpiphanyISD::FM_A_S: return "EpiphanyISD::FM_A_S"; + + default: return NULL; + } +} + +static const uint16_t EpiphanyArgRegs[] = { + Epiphany::R0, Epiphany::R1, Epiphany::R2, Epiphany::R3 +}; +static const unsigned NumArgRegs = llvm::array_lengthof(EpiphanyArgRegs); + +#include "EpiphanyGenCallingConv.inc" + +CCAssignFn *EpiphanyTargetLowering::CCAssignFnForNode(CallingConv::ID CC) const { + + switch(CC) { + default: llvm_unreachable("Unsupported calling convention"); + case CallingConv::C: + return CC_A64_APCS; + } +} + +void +EpiphanyTargetLowering::SaveVarArgRegisters(CCState &CCInfo, SelectionDAG &DAG, + DebugLoc DL, SDValue &Chain) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + EpiphanyMachineFunctionInfo *FuncInfo + = MF.getInfo(); + + SmallVector MemOps; + + unsigned FirstVariadicGPR = CCInfo.getFirstUnallocated(EpiphanyArgRegs, + NumArgRegs); + + unsigned GPRSaveSize = 4 * (NumArgRegs - FirstVariadicGPR); + int GPRIdx = 0; + if (GPRSaveSize != 0) { + GPRIdx = MFI->CreateStackObject(GPRSaveSize, 4, false); + + SDValue FIN = DAG.getFrameIndex(GPRIdx, getPointerTy()); + + for (unsigned i = FirstVariadicGPR; i < NumArgRegs; ++i) { + unsigned VReg = MF.addLiveIn(EpiphanyArgRegs[i], &Epiphany::GPR32RegClass); + SDValue Val = DAG.getCopyFromReg(Chain, DL, VReg, MVT::i32); + SDValue Store = DAG.getStore(Val.getValue(1), DL, Val, FIN, + MachinePointerInfo::getStack(i * 4), + false, false, 0); + MemOps.push_back(Store); + FIN = DAG.getNode(ISD::ADD, DL, getPointerTy(), FIN, + DAG.getConstant(4, getPointerTy())); + } + } + + int StackIdx = MFI->CreateFixedObject(4, CCInfo.getNextStackOffset(), true); + + FuncInfo->setVariadicStackIdx(StackIdx); + FuncInfo->setVariadicGPRIdx(GPRIdx); + FuncInfo->setVariadicGPRSize(GPRSaveSize); + FuncInfo->setVariadicFPRIdx(0); + FuncInfo->setVariadicFPRSize(0); + + if (!MemOps.empty()) { + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, &MemOps[0], + MemOps.size()); + } +} + + +SDValue +EpiphanyTargetLowering::LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + EpiphanyMachineFunctionInfo *FuncInfo = MF.getInfo(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + //bool TailCallOpt = MF.getTarget().Options.GuaranteedTailCallOpt; + + SmallVector ArgLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForNode(CallConv)); + + SmallVector ArgValues; + + SDValue ArgValue; + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + + if (VA.isRegLoc()) { + MVT RegVT = VA.getLocVT(); + const TargetRegisterClass *RC = getRegClassFor(RegVT); + unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC); + ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT); + + switch (VA.getLocInfo()) { + default: llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: break; + case CCValAssign::BCvt: + ArgValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), ArgValue); + break; + case CCValAssign::SExt: + ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue, DAG.getValueType(VA.getValVT())); + ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); + break; + case CCValAssign::ZExt: + ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue, DAG.getValueType(VA.getValVT())); + ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); + break; + } + + } else { // VA.isRegLoc() + assert(VA.isMemLoc()); + // hm. byval? + int FI = MFI->CreateFixedObject(VA.getLocVT().getSizeInBits()/8, VA.getLocMemOffset(), true); + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); + ArgValue = DAG.getLoad(VA.getLocVT(), dl, Chain, FIN, MachinePointerInfo::getFixedStack(FI),false, false, false, 0); + } + + InVals.push_back(ArgValue); + } + + if (isVarArg) + SaveVarArgRegisters(CCInfo, DAG, dl, Chain); + + unsigned StackArgSize = CCInfo.getNextStackOffset(); + // Even if we're not expected to free up the space, it's useful to know how + // much is there while considering tail calls (because we can reuse it). + FuncInfo->setBytesInStackArgArea(StackArgSize); + + return Chain; +} + +SDValue +EpiphanyTargetLowering::LowerFNEG(SDValue Op, SelectionDAG &DAG) const{ + DebugLoc dl = Op.getDebugLoc(); + SDValue Operand0 = Op.getOperand(0); + EVT VT = Op.getValueType(); + + // y = fneg(x) -> xor rd, 0x80000000 + SDValue Val = DAG.getConstant(0x80000000, MVT::i32); + SDValue Arg = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Operand0); + SDValue Xor = DAG.getNode(ISD::XOR, dl, MVT::i32, Arg, Val); + return DAG.getNode(ISD::BITCAST, dl, VT, Xor); +} + +SDValue +EpiphanyTargetLowering::LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + DebugLoc dl, SelectionDAG &DAG) const { + // CCValAssign - represent the assignment of the return value to a location. + SmallVector RVLocs; + + // CCState - Info about the registers and stack slots. + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), RVLocs, *DAG.getContext()); + + // Analyze outgoing return values. + CCInfo.AnalyzeReturn(Outs, CCAssignFnForNode(CallConv)); + + SDValue Flag; + SmallVector RetOps(1, Chain); + + for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) { + // PCS: "If the type, T, of the result of a function is such that + // void func(T arg) would require that arg be passed as a value in a + // register (or set of registers) according to the rules in 5.4, then the + // result is returned in the same registers as would be used for such an + // argument. + // + // Otherwise, the caller shall reserve a block of memory of sufficient + // size and alignment to hold the result. The address of the memory block + // shall be passed as an additional argument to the function in x8." + // + // This is implemented in two places. The register-return values are dealt + // with here, more complex returns are passed as an sret parameter, which + // means we don't have to worry about it during actual return. + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Only register-returns should be created by PCS"); + + + SDValue Arg = OutVals[i]; + + // There's no convenient note in the ABI about this as there is for normal + // arguments, but it says return values are passed in the same registers as + // an argument would be. I believe that includes the comments about + // unspecified higher bits, putting the burden of widening on the *caller* + // for return values. + switch (VA.getLocInfo()) { + default: llvm_unreachable("Unknown loc info"); + case CCValAssign::Full: break; + case CCValAssign::SExt: + case CCValAssign::ZExt: + case CCValAssign::AExt: + // Floating-point values should only be extended when they're going into + // memory, which can't happen here so an integer extend is acceptable. + Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::BCvt: + Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg); + break; + } + + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), Arg, Flag); + 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(EpiphanyISD::Ret, dl, MVT::Other, + &RetOps[0], RetOps.size()); +} + +SDValue +EpiphanyTargetLowering::LowerCall(CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { + SelectionDAG &DAG = CLI.DAG; + DebugLoc &dl = CLI.DL; + SmallVector &Outs = CLI.Outs; + SmallVector &OutVals = CLI.OutVals; + SmallVector &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &IsTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool IsVarArg = CLI.IsVarArg; + + MachineFunction &MF = DAG.getMachineFunction(); + EpiphanyMachineFunctionInfo *FuncInfo = MF.getInfo(); + //bool TailCallOpt = MF.getTarget().Options.GuaranteedTailCallOpt; + bool IsStructRet = !Outs.empty() && Outs[0].Flags.isSRet(); + + + if (IsTailCall) { + IsTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, IsVarArg, IsStructRet, MF.getFunction()->hasStructRetAttr(), Outs, OutVals, Ins, DAG); + } + + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeCallOperands(Outs, CCAssignFnForNode(CallConv)); + + // On Epiphany (and all other architectures I'm aware of) the most this has to + // do is adjust the stack pointer. + unsigned NumBytes = RoundUpToAlignment(CCInfo.getNextStackOffset(), 4); + + Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(NumBytes, true)); + + SDValue StackPtr = DAG.getCopyFromReg(Chain, dl, Epiphany::SP, getPointerTy()); + + SmallVector MemOpChains; + SmallVector, 8> RegsToPass; + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + ISD::ArgFlagsTy Flags = Outs[i].Flags; + SDValue Arg = OutVals[i]; + + // Callee does the actual widening, so all extensions just use an implicit + // definition of the rest of the Loc. Aesthetically, this would be nicer as + // an ANY_EXTEND, but that isn't valid for floating-point types and this + // alternative works on integer types too. + switch (VA.getLocInfo()) { + default: llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: break; + case CCValAssign::SExt: + case CCValAssign::ZExt: + case CCValAssign::AExt: { + // Floating-point arguments only get extended/truncated if they're going + // in memory, so using the integer operation is acceptable here. + Arg = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), Arg); + break; + } + case CCValAssign::BCvt: + Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg); + break; + } + + if (VA.isRegLoc()) { + // A normal register (sub-) argument. For now we just note it down because + // we want to copy things into registers as late as possible to avoid + // register-pressure (and possibly worse). + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + continue; + } + + assert(VA.isMemLoc() && "unexpected argument location"); + + SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset()); + SDValue DstAddr = DAG.getNode(ISD::ADD, dl, getPointerTy(), StackPtr, PtrOff); + MachinePointerInfo DstInfo = MachinePointerInfo::getStack(VA.getLocMemOffset()); + + + if (Flags.isByVal()) { + SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), MVT::i32); + SDValue Cpy = DAG.getMemcpy(Chain, dl, DstAddr, Arg, SizeNode, + Flags.getByValAlign(), + /*isVolatile = */ false, + /*alwaysInline = */ false, + DstInfo, MachinePointerInfo(0)); + MemOpChains.push_back(Cpy); + } else { + // Normal stack argument, put it where it's needed. + SDValue Store = DAG.getStore(Chain, dl, Arg, DstAddr, DstInfo, false, false, 0); + MemOpChains.push_back(Store); + } + } + + // The loads and stores generated above shouldn't clash with each + // other. Combining them with this TokenFactor notes that fact for the rest of + // the backend. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &MemOpChains[0], MemOpChains.size()); + + // Most of the rest of the instructions need to be glued together; we don't + // want assignments to actual registers used by a call to be rearranged by a + // well-meaning scheduler. + SDValue InFlag; + + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + // The linker is responsible for inserting veneers when necessary to put a + // function call destination in range, so we don't need to bother with a + // wrapper here. + if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + const GlobalValue *GV = G->getGlobal(); + Callee = DAG.getTargetGlobalAddress(GV, dl, getPointerTy()); + } else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { + const char *Sym = S->getSymbol(); + Callee = DAG.getTargetExternalSymbol(Sym, getPointerTy()); + } + + // We produce the following DAG scheme for the actual call instruction: + // (EpiphanyCall Chain, Callee, reg1, ..., regn, preserveMask, inflag? + // + // Most arguments aren't going to be used and just keep the values live as + // far as LLVM is concerned. It's expected to be selected as simply "bl + // callee" (for a direct, non-tail call). + std::vector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(DAG.getRegister(RegsToPass[i].first, RegsToPass[i].second.getValueType())); + + // Add a register mask operand representing the call-preserved registers. This + // is used later in codegen to constrain register-allocation. + const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo(); + const uint32_t *Mask = TRI->getCallPreservedMask(CallConv); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + + // If we needed glue, put it in as the last argument. + if (InFlag.getNode()) + Ops.push_back(InFlag); + + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + + Chain = DAG.getNode(EpiphanyISD::Call, dl, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + + // Now we can reclaim the stack, just as well do it before working out where + // our return value is. + + uint64_t CalleePopBytes = /*DoesCalleeRestoreStack(CallConv, TailCallOpt) ? NumBytes :*/ 0; + + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, true), + DAG.getIntPtrConstant(CalleePopBytes, true), + InFlag); + InFlag = Chain.getValue(1); + + + return LowerCallResult(Chain, InFlag, CallConv, IsVarArg, Ins, dl, DAG, InVals); +} + +SDValue +EpiphanyTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + // Assign locations to each value returned by this call. + SmallVector RVLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), + getTargetMachine(), RVLocs, *DAG.getContext()); + CCInfo.AnalyzeCallResult(Ins, CCAssignFnForNode(CallConv)); + + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign VA = RVLocs[i]; + + // Return values that are too big to fit into registers should use an sret + // pointer, so this can be a lot simpler than the main argument code. + assert(VA.isRegLoc() && "Memory locations not expected for call return"); + + SDValue Val = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), VA.getLocVT(), + InFlag); + Chain = Val.getValue(1); + InFlag = Val.getValue(2); + + switch (VA.getLocInfo()) { + default: llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: break; + case CCValAssign::BCvt: + Val = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), Val); + break; + case CCValAssign::ZExt: + case CCValAssign::SExt: + case CCValAssign::AExt: + // Floating-point arguments only get extended/truncated if they're going + // in memory, so using the integer operation is acceptable here. + Val = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), Val); + break; + } + + InVals.push_back(Val); + } + + return Chain; +} + + +SDValue EpiphanyTargetLowering::addTokenForArgument(SDValue Chain, + SelectionDAG &DAG, + MachineFrameInfo *MFI, + int ClobberedFI) const { + SmallVector ArgChains; + int64_t FirstByte = MFI->getObjectOffset(ClobberedFI); + int64_t LastByte = FirstByte + MFI->getObjectSize(ClobberedFI) - 1; + + // Include the original chain at the beginning of the list. When this is + // used by target LowerCall hooks, this helps legalize find the + // CALLSEQ_BEGIN node. + ArgChains.push_back(Chain); + + // Add a chain value for each stack argument corresponding + for (SDNode::use_iterator U = DAG.getEntryNode().getNode()->use_begin(), + UE = DAG.getEntryNode().getNode()->use_end(); U != UE; ++U) + if (LoadSDNode *L = dyn_cast(*U)) + if (FrameIndexSDNode *FI = dyn_cast(L->getBasePtr())) + if (FI->getIndex() < 0) { + int64_t InFirstByte = MFI->getObjectOffset(FI->getIndex()); + int64_t InLastByte = InFirstByte; + InLastByte += MFI->getObjectSize(FI->getIndex()) - 1; + + if ((InFirstByte <= FirstByte && FirstByte <= InLastByte) || + (FirstByte <= InFirstByte && InFirstByte <= LastByte)) + ArgChains.push_back(SDValue(L, 1)); + } + + // Build a tokenfactor for all the chains. + return DAG.getNode(ISD::TokenFactor, Chain.getDebugLoc(), MVT::Other, + &ArgChains[0], ArgChains.size()); +} + +static EpiphanyCC::CondCodes IntCCToEpiphanyCC(ISD::CondCode CC) { + switch (CC) { + case ISD::SETEQ: return EpiphanyCC::EQ; + case ISD::SETGT: return EpiphanyCC::GT; + case ISD::SETGE: return EpiphanyCC::GTE; + case ISD::SETLT: return EpiphanyCC::LT; + case ISD::SETLE: return EpiphanyCC::LTE; + case ISD::SETNE: return EpiphanyCC::NE; + case ISD::SETUGT: return EpiphanyCC::GTU; + case ISD::SETUGE: return EpiphanyCC::GTEU; + case ISD::SETULT: return EpiphanyCC::LTU; + case ISD::SETULE: return EpiphanyCC::LTEU; + default: llvm_unreachable("Unexpected condition code"); + } +} + +bool EpiphanyTargetLowering::isLegalICmpImmediate(int64_t Val) const { + // icmp is implemented using adds/subs immediate with a 11bit signed imm + // Symmetric by using adds/subs + if (Val < 0) + Val = -Val; + + // 11bit imm -> 10 bit unsigned + 1 sign bit + return (Val & ~0x3FF) == 0; +} + +SDValue EpiphanyTargetLowering::getSelectableIntSetCC(SDValue LHS, SDValue RHS, + ISD::CondCode CC, SDValue &A64cc, + SelectionDAG &DAG, DebugLoc &dl) const { + if (ConstantSDNode *RHSC = dyn_cast(RHS.getNode())) { + int64_t C = 0; + EVT VT = RHSC->getValueType(0); + bool knownInvalid = false; + + // I'm not convinced the rest of LLVM handles these edge cases properly, but + // we can at least get it right. + if (isSignedIntSetCC(CC)) { + C = RHSC->getSExtValue(); + } else if (RHSC->getZExtValue() > INT64_MAX) { + // A 64-bit constant not representable by a signed 64-bit integer is far + // too big to fit into a SUBS immediate anyway. + knownInvalid = true; + } else { + C = RHSC->getZExtValue(); + } + + if (!knownInvalid && !isLegalICmpImmediate(C)) { + // Constant does not fit, try adjusting it by one? + switch (CC) { + default: break; + case ISD::SETLT: + case ISD::SETGE: + if (isLegalICmpImmediate(C-1)) { + CC = (CC == ISD::SETLT) ? ISD::SETLE : ISD::SETGT; + RHS = DAG.getConstant(C-1, VT); + } + break; + case ISD::SETULT: + case ISD::SETUGE: + if (isLegalICmpImmediate(C-1)) { + CC = (CC == ISD::SETULT) ? ISD::SETULE : ISD::SETUGT; + RHS = DAG.getConstant(C-1, VT); + } + break; + case ISD::SETLE: + case ISD::SETGT: + if (isLegalICmpImmediate(C+1)) { + CC = (CC == ISD::SETLE) ? ISD::SETLT : ISD::SETGE; + RHS = DAG.getConstant(C+1, VT); + } + break; + case ISD::SETULE: + case ISD::SETUGT: + if (isLegalICmpImmediate(C+1)) { + CC = (CC == ISD::SETULE) ? ISD::SETULT : ISD::SETUGE; + RHS = DAG.getConstant(C+1, VT); + } + break; + } + } + } + + EpiphanyCC::CondCodes CondCode = IntCCToEpiphanyCC(CC); + A64cc = DAG.getConstant(CondCode, MVT::i32); + return DAG.getNode(EpiphanyISD::SETCC, dl, MVT::i32, LHS, RHS, + DAG.getCondCode(CC)); +} + +static EpiphanyCC::CondCodes FPCCToEpiphanyCC(ISD::CondCode CC, bool& invert) { + EpiphanyCC::CondCodes CondCode = EpiphanyCC::Invalid; + invert = 0; + + switch (CC) { + default: llvm_unreachable("Unknown FP condition!"); + case ISD::SETEQ: + case ISD::SETOEQ: + case ISD::SETUEQ: CondCode = EpiphanyCC::BEQ; break; + + case ISD::SETNE: + case ISD::SETUNE: + case ISD::SETONE: CondCode = EpiphanyCC::BNE; break; + + case ISD::SETGT: + case ISD::SETOGT: + case ISD::SETUGT: CondCode = EpiphanyCC::BLT; invert = 1; break; + + case ISD::SETGE: + case ISD::SETOGE: + case ISD::SETUGE: CondCode = EpiphanyCC::BLTE; invert = 1; break; + + case ISD::SETLT: + case ISD::SETULT: + case ISD::SETOLT: CondCode = EpiphanyCC::BLT; break; + + case ISD::SETLE: + case ISD::SETULE: + case ISD::SETOLE: CondCode = EpiphanyCC::BLTE; break; + + //case ISD::SETO: + //case ISD::SETUO: ooops. call? + } + return CondCode; +} + +SDValue +EpiphanyTargetLowering::LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const { + DebugLoc DL = Op.getDebugLoc(); + EVT PtrVT = getPointerTy(); + const BlockAddress *BA = cast(Op)->getBlockAddress(); + + assert(getTargetMachine().getCodeModel() == CodeModel::Small + && "Only small code model supported at the moment"); + + // The most efficient code is PC-relative anyway for the small memory model, + // so we don't need to worry about relocation model. + return DAG.getNode(EpiphanyISD::WrapperSmall, DL, PtrVT, + DAG.getTargetBlockAddress(BA, PtrVT, 0, + EpiphanyII::MO_HI16), + DAG.getTargetBlockAddress(BA, PtrVT, 0, + EpiphanyII::MO_LO16), + DAG.getConstant(/*Alignment=*/ 4, MVT::i32)); +} + + +// (BRCOND chain, val, dest) +SDValue +EpiphanyTargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + SDValue Chain = Op.getOperand(0); + SDValue TheBit = Op.getOperand(1); + SDValue DestBB = Op.getOperand(2); + + // Epiphany BooleanContents is the default UndefinedBooleanContent, which means + // that as the consumer we are responsible for ignoring rubbish in higher + // bits. + TheBit = DAG.getNode(ISD::AND, dl, MVT::i32, TheBit, + DAG.getConstant(1, MVT::i32)); + + SDValue A64CMP = DAG.getNode(EpiphanyISD::SETCC, dl, MVT::i32, TheBit, + DAG.getConstant(0, TheBit.getValueType()), + DAG.getCondCode(ISD::SETNE)); + + return DAG.getNode(EpiphanyISD::BR_CC, dl, MVT::Other, Chain, + A64CMP, DAG.getConstant(EpiphanyCC::NE, MVT::i32), + DestBB); +} + +// (BR_CC chain, condcode, lhs, rhs, dest) +SDValue +EpiphanyTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue DestBB = Op.getOperand(4); + + if (LHS.getValueType().isInteger()) { + SDValue A64cc; + + // Integers are handled in a separate function because the combinations of + // immediates and tests can get hairy and we may want to fiddle things. + SDValue CmpOp = getSelectableIntSetCC(LHS, RHS, CC, A64cc, DAG, dl); + + return DAG.getNode(EpiphanyISD::BR_CC, dl, MVT::Other, + Chain, CmpOp, A64cc, DestBB); + } + + EpiphanyCC::CondCodes CondCode; + bool invert; + SDValue SetCC; + CondCode = FPCCToEpiphanyCC(CC, invert); + SDValue A64cc = DAG.getConstant(CondCode, MVT::i32); + if(invert) + std::swap(LHS, RHS); + SetCC = DAG.getNode(EpiphanyISD::SETCC, dl, MVT::i32, LHS, RHS, DAG.getCondCode(CC)); + SDValue A64BR_CC = DAG.getNode(EpiphanyISD::BR_CC, dl, MVT::Other, Chain, SetCC, A64cc, DestBB); + + return A64BR_CC; +} + +SDValue +EpiphanyTargetLowering::LowerGlobalAddressELF(SDValue Op, + SelectionDAG &DAG) const { + // TableGen doesn't have easy access to the CodeModel or RelocationModel, so + // we make that distinction here. + + // We support the small memory model for now. + assert(getTargetMachine().getCodeModel() == CodeModel::Small); + + EVT PtrVT = getPointerTy(); + DebugLoc dl = Op.getDebugLoc(); + const GlobalAddressSDNode *GN = cast(Op); + const GlobalValue *GV = GN->getGlobal(); + unsigned Alignment = GV->getAlignment(); + Reloc::Model RelocM = getTargetMachine().getRelocationModel(); + + //DAG.viewGraph(); + //DAG.dump(); + + + if (GV->isWeakForLinker() && RelocM == Reloc::Static) { + // Weak symbols can't use ADRP/ADD pair since they should evaluate to + // zero when undefined. In PIC mode the GOT can take care of this, but in + // absolute mode we use a constant pool load. + SDValue PoolAddr; + PoolAddr = DAG.getNode(EpiphanyISD::WrapperSmall, dl, PtrVT, + DAG.getTargetConstantPool(GV, PtrVT, 0, 0, EpiphanyII::MO_HI16), + DAG.getTargetConstantPool(GV, PtrVT, 0, 0, EpiphanyII::MO_LO16), + DAG.getConstant(4, MVT::i32)); + return DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), PoolAddr, + MachinePointerInfo::getConstantPool(), + /*isVolatile=*/ false, /*isNonTemporal=*/ true, + /*isInvariant=*/ true, 4); + } + + if (Alignment == 0) { + const PointerType *GVPtrTy = cast(GV->getType()); + if (GVPtrTy->getElementType()->isSized()) { + Alignment = getDataLayout()->getABITypeAlignment(GVPtrTy->getElementType()); + } else { + // Be conservative if we can't guess, not that it really matters: + // functions and labels aren't valid for loads, and the methods used to + // actually calculate an address work with any alignment. + Alignment = 1; + } + } + + SDValue GlobalRef = DAG.getNode(EpiphanyISD::WrapperSmall, dl, PtrVT, + DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, EpiphanyII::MO_HI16), + DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, EpiphanyII::MO_LO16), + DAG.getConstant(Alignment, MVT::i32)); + + if (GN->getOffset() != 0) + return DAG.getNode(ISD::ADD, dl, PtrVT, GlobalRef, DAG.getConstant(GN->getOffset(), PtrVT)); + + return GlobalRef; +} + +SDValue +EpiphanyTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const { + JumpTableSDNode *JT = cast(Op); + DebugLoc dl = JT->getDebugLoc(); + + // When compiling PIC, jump tables get put in the code section so a static + // relocation-style is acceptable for both cases. + return DAG.getNode(EpiphanyISD::WrapperSmall, dl, getPointerTy(), + DAG.getTargetJumpTable(JT->getIndex(), getPointerTy(), EpiphanyII::MO_HI16), + DAG.getTargetJumpTable(JT->getIndex(), getPointerTy(), EpiphanyII::MO_LO16), + DAG.getConstant(1, MVT::i32)); +} + +// (SELECT_CC lhs, rhs, iftrue, iffalse, condcode) +SDValue +EpiphanyTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + SDValue IfTrue = Op.getOperand(2); + SDValue IfFalse = Op.getOperand(3); + ISD::CondCode CC = cast(Op.getOperand(4))->get(); + + if (LHS.getValueType().isInteger()) { + SDValue A64cc; + + // Integers are handled in a separate function because the combinations of + // immediates and tests can get hairy and we may want to fiddle things. + SDValue CmpOp = getSelectableIntSetCC(LHS, RHS, CC, A64cc, DAG, dl); + + return DAG.getNode(EpiphanyISD::SELECT_CC, dl, Op.getValueType(), + CmpOp, IfTrue, IfFalse, A64cc); + } + + + EpiphanyCC::CondCodes CondCode; + bool invert; + SDValue SetCC; + CondCode = FPCCToEpiphanyCC(CC, invert); + SDValue A64cc = DAG.getConstant(CondCode, MVT::i32); + if(invert) + std::swap(LHS, RHS); + SetCC = DAG.getNode(EpiphanyISD::SETCC, dl, MVT::i32, LHS, RHS, DAG.getCondCode(CC)); + SDValue A64SELECT_CC = DAG.getNode(EpiphanyISD::SELECT_CC, dl, Op.getValueType(), SetCC, IfTrue, IfFalse, A64cc); + + return A64SELECT_CC; +} + +// (SELECT testbit, iftrue, iffalse) +SDValue +EpiphanyTargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + SDValue TheBit = Op.getOperand(0); + SDValue IfTrue = Op.getOperand(1); + SDValue IfFalse = Op.getOperand(2); + + // Epiphany BooleanContents is the default UndefinedBooleanContent, which means + // that as the consumer we are responsible for ignoring rubbish in higher + // bits. + TheBit = DAG.getNode(ISD::AND, dl, MVT::i32, TheBit, + DAG.getConstant(1, MVT::i32)); + SDValue A64CMP = DAG.getNode(EpiphanyISD::SETCC, dl, MVT::i32, TheBit, + DAG.getConstant(0, TheBit.getValueType()), + DAG.getCondCode(ISD::SETNE)); + + return DAG.getNode(EpiphanyISD::SELECT_CC, dl, Op.getValueType(), + A64CMP, IfTrue, IfFalse, + DAG.getConstant(EpiphanyCC::NE, MVT::i32)); +} + +// (SETCC lhs, rhs, condcode) +SDValue +EpiphanyTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + ISD::CondCode CC = cast(Op.getOperand(2))->get(); + EVT VT = Op.getValueType(); + + if (LHS.getValueType().isInteger()) { + SDValue A64cc; + + // Integers are handled in a separate function because the combinations of + // immediates and tests can get hairy and we may want to fiddle things. + SDValue CmpOp = getSelectableIntSetCC(LHS, RHS, CC, A64cc, DAG, dl); + + return DAG.getNode(EpiphanyISD::SELECT_CC, dl, VT, + CmpOp, DAG.getConstant(1, VT), DAG.getConstant(0, VT), + A64cc); + } + + EpiphanyCC::CondCodes CondCode; + bool invert; + SDValue CmpOp; + CondCode = FPCCToEpiphanyCC(CC, invert); + SDValue A64cc = DAG.getConstant(CondCode, MVT::i32); + if(invert) + std::swap(LHS, RHS); + CmpOp = DAG.getNode(EpiphanyISD::SETCC, dl, MVT::i32, LHS, RHS, DAG.getCondCode(CC)); + SDValue A64SELECT_CC = DAG.getNode(EpiphanyISD::SELECT_CC, dl, VT, CmpOp, DAG.getConstant(1, VT), DAG.getConstant(0, VT), A64cc); + + return A64SELECT_CC; +} + +SDValue +EpiphanyTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + default: llvm_unreachable("Don't know how to custom lower this!"); + + case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); + case ISD::BRCOND: return LowerBRCOND(Op, DAG); + case ISD::BR_CC: return LowerBR_CC(Op, DAG); + case ISD::FNEG: return LowerFNEG(Op, DAG); + case ISD::GlobalAddress: return LowerGlobalAddressELF(Op, DAG); + case ISD::JumpTable: return LowerJumpTable(Op, DAG); + case ISD::SELECT: return LowerSELECT(Op, DAG); + case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); + case ISD::SETCC: return LowerSETCC(Op, DAG); + } + + return SDValue(); +} + + +SDValue +PerformFSUBCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI){ + +SDValue N0 = N->getOperand(0); +SDValue N1 = N->getOperand(1); +EVT VT = N->getValueType(0); +DebugLoc dl = N->getDebugLoc(); +SelectionDAG &DAG = DCI.DAG; + + // FSUB -> FMA combines: + + // fold (fsub (fmul x, y), z) -> (fma x, y, (fneg z)) + if (N0.getOpcode() == ISD::FMUL && N0->hasOneUse()) { + return DAG.getNode(EpiphanyISD::FM_A_S, N->getDebugLoc(), VT, N0.getOperand(0), N0.getOperand(1), N1, DAG.getConstant(1, MVT::i32)); + } + + // fold (fsub x, (fmul y, z)) -> (fma (fneg y), z, x) + // Note: Commutes FSUB operands. + if (N1.getOpcode() == ISD::FMUL && N1->hasOneUse()) { + return DAG.getNode(EpiphanyISD::FM_A_S, N->getDebugLoc(), VT, N1.getOperand(0), N1.getOperand(1), N0, DAG.getConstant(1, MVT::i32)); + } + + // fold (fsub (-(fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) + //if (N0.getOpcode() == ISD::FNEG && + // N0.getOperand(0).getOpcode() == ISD::FMUL && + // N0->hasOneUse() && N0.getOperand(0).hasOneUse()) { + // SDValue N00 = N0.getOperand(0).getOperand(0); + // SDValue N01 = N0.getOperand(0).getOperand(1); + // return DAG.getNode(ISD::FMA, dl, VT, + // DAG.getNode(ISD::FNEG, dl, VT, N00), N01, + // DAG.getNode(ISD::FNEG, dl, VT, N1)); + //} + return SDValue(); +} + +SDValue +PerformFADDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI){ + +SDValue N0 = N->getOperand(0); +SDValue N1 = N->getOperand(1); +EVT VT = N->getValueType(0); +DebugLoc dl = N->getDebugLoc(); +SelectionDAG &DAG = DCI.DAG; + + // FADD -> FMA combines: + // fold (fadd (fmul x, y), z) -> (fma x, y, z) + if (N0.getOpcode() == ISD::FMUL && N0->hasOneUse()) { + return DAG.getNode(EpiphanyISD::FM_A_S, N->getDebugLoc(), VT, N0.getOperand(0), N0.getOperand(1), N1, DAG.getConstant(0, MVT::i32)); + } + + // fold (fadd x, (fmul y, z)) -> (fma y, z, x) + // Note: Commutes FADD operands. + if (N1.getOpcode() == ISD::FMUL && N1->hasOneUse()) { + return DAG.getNode(EpiphanyISD::FM_A_S, N->getDebugLoc(), VT, N1.getOperand(0), N1.getOperand(1), N0, DAG.getConstant(0, MVT::i32)); + } + + return SDValue(); +} + +SDValue +EpiphanyTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { + switch (N->getOpcode()) { + case ISD::FADD: return PerformFADDCombine(N, DCI); + case ISD::FSUB: return PerformFSUBCombine(N, DCI); + default: break; + } + return SDValue(); +} + diff --git a/EpiphanyISelLowering.h b/EpiphanyISelLowering.h new file mode 100644 index 0000000..767ea58 --- /dev/null +++ b/EpiphanyISelLowering.h @@ -0,0 +1,155 @@ +//==-- EpiphanyISelLowering.h - Epiphany DAG Lowering Interface ----*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that Epiphany uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_EPIPHANY_ISELLOWERING_H +#define LLVM_TARGET_EPIPHANY_ISELLOWERING_H + +#include "Utils/EpiphanyBaseInfo.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLowering.h" + + +namespace llvm { +namespace EpiphanyISD { + enum NodeType { + // Start the numbering from where ISD NodeType finishes. + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + // This is a conditional branch which also notes the flag needed + // (eq/sgt/...). A64 puts this information on the branches rather than + // compares as LLVM does. + BR_CC, + + // A node to be selected to an actual call operation: either BL or BLR in + // the absence of tail calls. + Call, + + // Simply a convenient node inserted during ISelLowering to represent + // procedure return. Will almost certainly be selected to "RET". + Ret, + + /// This is an A64-ification of the standard LLVM SELECT_CC operation. The + /// main difference is that it only has the values and an A64 condition, + /// which will be produced by a setcc instruction. + SELECT_CC, + + /// This serves most of the functions of the LLVM SETCC instruction, for two + /// purposes. First, it prevents optimisations from fiddling with the + /// compare after we've moved the CondCode information onto the SELECT_CC or + /// BR_CC instructions. Second, it gives a legal instruction for the actual + /// comparison. + /// + /// It keeps a record of the condition flags asked for because certain + /// instructions are only valid for a subset of condition codes. + SETCC, + + // Wraps an address which the ISelLowering phase has decided should be + // created using the small absolute memory model: i.e. adrp/add or + // adrp/mem-op. This exists to prevent bare TargetAddresses which may never + // get selected. + WrapperSmall, + + // Node for FMA and FMS + FM_A_S + }; +} + + +class EpiphanySubtarget; +class EpiphanyTargetMachine; + +class EpiphanyTargetLowering : public TargetLowering { +public: + explicit EpiphanyTargetLowering(EpiphanyTargetMachine &TM); + + const char *getTargetNodeName(unsigned Opcode) const; + + CCAssignFn *CCAssignFnForNode(CallingConv::ID CC) const; + + SDValue LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + DebugLoc dl, SelectionDAG &DAG) const; + + SDValue LowerCall(CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const; + + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + void SaveVarArgRegisters(CCState &CCInfo, SelectionDAG &DAG, + DebugLoc DL, SDValue &Chain) const; + + + /// Finds the incoming stack arguments which overlap the given fixed stack + /// object and incorporates their load into the current chain. This prevents + /// an upcoming store from clobbering the stack argument before it's used. + SDValue addTokenForArgument(SDValue Chain, SelectionDAG &DAG, + MachineFrameInfo *MFI, int ClobberedFI) const; + + EVT getSetCCResultType(EVT VT) const; + + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + + bool isLegalICmpImmediate(int64_t Val) const; + SDValue getSelectableIntSetCC(SDValue LHS, SDValue RHS, ISD::CondCode CC, + SDValue &A64cc, SelectionDAG &DAG, DebugLoc &dl) const; + + virtual MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; + + SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBRCOND(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFNEG(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalAddressELF(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const; + + virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const; + + //nope. + bool IsEligibleForTailCallOptimization(SDValue Callee, + CallingConv::ID CalleeCC, + bool IsVarArg, + bool IsCalleeStructRet, + bool IsCallerStructRet, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + const SmallVectorImpl &Ins, + SelectionDAG& DAG) const { return false;} +// custom fma due to fneg, so we say no + virtual bool isFMAFasterThanMulAndAdd(EVT) const { return false; } + +private: + const EpiphanySubtarget *Subtarget; + const TargetRegisterInfo *RegInfo; + const InstrItineraryData *Itins; +}; +} // namespace llvm + +#endif // LLVM_TARGET_EPIPHANY_ISELLOWERING_H diff --git a/EpiphanyInstrFormats.td b/EpiphanyInstrFormats.td new file mode 100644 index 0000000..4734d77 --- /dev/null +++ b/EpiphanyInstrFormats.td @@ -0,0 +1,93 @@ +//===- EpiphanyInstrFormats.td - Epiphany Instruction Formats --*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This file describes Epiphany instruction formats, down to the level of the +// instruction's overall class. +// ===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// A64 Instruction Format Definitions. +//===----------------------------------------------------------------------===// + +class PseudoInst patterns> : Instruction { + let Namespace = "Epiphany"; + + let OutOperandList = outs; + let InOperandList= ins; + let Pattern = patterns; + let isCodeGenOnly = 1; + let isPseudo = 1; + let Size = 4; +} + +// As above, this will be a single A64 instruction, but we can actually give the +// expansion in TableGen. +class A64PseudoExpand patterns, dag Result> + : PseudoInst, + PseudoInstExpansion; + + +class EP1INST patterns, InstrItinClass itin> : Instruction { + +field bits<32> Inst =0 ; + // LLVM-level model of the Epiphany/A64 distinction. + let Namespace = "Epiphany"; + let Size = 4; + + // Set the templated fields + let OutOperandList = outs; + let InOperandList = ins; + let AsmString = asmstr; + let Pattern = patterns; + let Itinerary = itin; +} + +class EP2INST patterns, InstrItinClass itin> : Instruction { + +field bits<32> Inst =0 ; + // LLVM-level model of the Epiphany/A64 distinction. + let Namespace = "Epiphany"; + let Size = 4; + + // Set the templated fields + let OutOperandList = outs; + let InOperandList = ins; + let AsmString = asmstr; + let Pattern = patterns; + let Itinerary = itin; +} +class EP3INST patterns, InstrItinClass itin> : Instruction { + +field bits<32> Inst =0 ; + // LLVM-level model of the Epiphany/A64 distinction. + let Namespace = "Epiphany"; + let Size = 4; + + // Set the templated fields + let OutOperandList = outs; + let InOperandList = ins; + let AsmString = asmstr; + let Pattern = patterns; + let Itinerary = itin; +} + +class EP4INST patterns, InstrItinClass itin> : Instruction { + +field bits<32> Inst =0 ; + // LLVM-level model of the Epiphany/A64 distinction. + let Namespace = "Epiphany"; + let Size = 4; + + // Set the templated fields + let OutOperandList = outs; + let InOperandList = ins; + let AsmString = asmstr; + let Pattern = patterns; + let Itinerary = itin; +} \ No newline at end of file diff --git a/EpiphanyInstrInfo.cpp b/EpiphanyInstrInfo.cpp new file mode 100644 index 0000000..2a4c762 --- /dev/null +++ b/EpiphanyInstrInfo.cpp @@ -0,0 +1,751 @@ +//===- EpiphanyInstrInfo.cpp - Epiphany Instruction Information -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Epiphany implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "Epiphany.h" +#include "EpiphanyInstrInfo.h" +#include "EpiphanyMachineFunctionInfo.h" +#include "EpiphanyTargetMachine.h" +#include "MCTargetDesc/EpiphanyMCTargetDesc.h" +#include "Utils/EpiphanyBaseInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Metadata.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#include + +#define GET_INSTRINFO_CTOR +#include "EpiphanyGenInstrInfo.inc" + +using namespace llvm; + +EpiphanyInstrInfo::EpiphanyInstrInfo(const EpiphanySubtarget &STI) + : EpiphanyGenInstrInfo(Epiphany::ADJCALLSTACKDOWN, Epiphany::ADJCALLSTACKUP), + RI(*this, STI), Subtarget(STI) {} + +void EpiphanyInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const { + + bool GPRDest = Epiphany::GPR32RegClass.contains(DestReg); + bool GPRSrc = Epiphany::GPR32RegClass.contains(SrcReg); + + if (GPRDest && GPRSrc) { + BuildMI(MBB, I, DL, get(Epiphany::MOVww), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + return; + } else if(!GPRDest && !GPRSrc) { + BuildMI(MBB, I, DL, get(Epiphany::MOVss), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + return; + } + + llvm_unreachable("Unknown register class in copyPhysReg"); + + + // //MDNode* comment = MDNode::get(getGlobalContext(), ArrayRef(llvm::MDString::get(getGlobalContext(), "BAH"))); + // // E.g. ORR xDst, xzr, xSrc, lsl #0 + // BuildMI(MBB, I, DL, get(Opc), DestReg) + // .addReg(ZeroReg) + // .addReg(SrcReg) + //.addImm(0);//.addMetadata(comment) +} + +MachineInstr * +EpiphanyInstrInfo::emitFrameIndexDebugValue(MachineFunction &MF, int FrameIx, + uint64_t Offset, const MDNode *MDPtr, + DebugLoc DL) const { + MachineInstrBuilder MIB = BuildMI(MF, DL, get(Epiphany::DBG_VALUE)) + .addFrameIndex(FrameIx).addImm(0) + .addImm(Offset) + .addMetadata(MDPtr); + return &*MIB; +} + + +bool +EpiphanyInstrInfo::analyzeCompare(const MachineInstr *MI, unsigned &SrcReg, unsigned &SrcReg2, + int &CmpMask, int &CmpValue) const { + switch (MI->getOpcode()) { + default: break; + case Epiphany::SUBri_cmp: + SrcReg = MI->getOperand(0).getReg(); + SrcReg2 = 0; + CmpMask = ~0; + CmpValue = MI->getOperand(1).getImm(); + return true; + case Epiphany::CMPrr: + SrcReg = MI->getOperand(0).getReg(); + SrcReg2 = MI->getOperand(1).getReg(); + CmpMask = ~0; + CmpValue = 0; + return true; + } + return false; +} + +/// OptimizeCompareInstr - Convert the instruction supplying the argument to the +/// comparison into one that sets the zero bit in the flags register. Convert +/// the SUBrr(r1,r2)|Subri(r1,CmpValue) instruction into one that sets the flags +/// register and remove the CMPrr(r1,r2)|CMPrr(r2,r1)|CMPri(r1,CmpValue) +/// instruction. +bool +EpiphanyInstrInfo::optimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, unsigned SrcReg2, int CmpMask, int CmpValue, const MachineRegisterInfo *MRI) const { + + MachineRegisterInfo::def_iterator DI = MRI->def_begin(SrcReg); + if (llvm::next(DI) != MRI->def_end()) + // Only support one definition. + return false; + + MachineInstr *MI = &*DI; + + // Get ready to iterate backward from CmpInstr. + MachineBasicBlock::iterator I = CmpInstr, E = MI, B = CmpInstr->getParent()->begin(); + + // Early exit if CmpInstr is at the beginning of the BB. + if (I == B) return false; + + // There are two possible candidates which can be changed to set CPSR: + // One is MI, the other is a SUB instruction. + // For CMPrr(r1,r2), we are looking for SUB(r1,r2) or SUB(r2,r1). + // For CMPri(r1, CmpValue), we are looking for SUBri(r1, CmpValue). + MachineInstr *Sub = NULL; + unsigned SrcReg2X = 0; + if (CmpInstr->getOpcode() == Epiphany::CMPrr) { + SrcReg2X = CmpInstr->getOperand(1).getReg(); + // MI is not a candidate for CMPrr. + MI = NULL; + } else if (MI->getParent() != CmpInstr->getParent() || CmpValue != 0) { + // Conservatively refuse to convert an instruction which isn't in the same + // BB as the comparison. + // For CMPri, we need to check Sub, thus we can't return here. + if(CmpInstr->getOpcode() == Epiphany::SUBri_cmp) + MI = NULL; + else + return false; + } + + // Check that CPSR isn't set between the comparison instruction and the one we + // want to change. At the same time, search for Sub. + --I; + for (; I != E; --I) { + const MachineInstr &Instr = *I; + + for (unsigned IO = 0, EO = Instr.getNumOperands(); IO != EO; ++IO) { + const MachineOperand &MO = Instr.getOperand(IO); + if (MO.isRegMask() && MO.clobbersPhysReg(Epiphany::NZCV)) + return false; + if (!MO.isReg()) continue; + + // This instruction modifies or uses CPSR after the one we want to + // change. We can't do this transformation. + if (MO.getReg() == Epiphany::NZCV) + return false; + } + + // Check whether the current instruction is SUB(r1, r2) or SUB(r2, r1). + if (SrcReg2X != 0 && Instr.getOpcode() == Epiphany::SUBrr && + ((Instr.getOperand(1).getReg() == SrcReg && + Instr.getOperand(2).getReg() == SrcReg2X) || + (Instr.getOperand(1).getReg() == SrcReg2X && + Instr.getOperand(2).getReg() == SrcReg))) { + Sub = &*I; + break; + } + + // Check whether the current instruction is SUBri(r1, CmpValue). + if ((CmpInstr->getOpcode() == Epiphany::SUBri_cmp) && + Instr.getOpcode() == Epiphany::SUBri && CmpValue != 0 && + Instr.getOperand(1).getReg() == SrcReg && + Instr.getOperand(2).getImm() == CmpValue) { + Sub = &*I; + break; + } + + if (I == B) + // The 'and' is below the comparison instruction. + return false; + } + + // Return false if no candidates exist. + if (!MI && !Sub) + return false; + + // The single candidate is called MI. + if (!MI) MI = Sub; + + switch (MI->getOpcode()) { + default: break; + case Epiphany::ADDrr: + case Epiphany::ADDri: + case Epiphany::SUBrr: + case Epiphany::SUBri: + case Epiphany::ANDrr: + case Epiphany::ORRrr: + case Epiphany::EORrr: { + // Scan forward for the use of CPSR + // When checking against MI: if it's a conditional code requires + // checking of V bit, then this is not safe to do. If we can't find the + // CPSR use (i.e. used in another block), then it's not safe to perform + // the optimization. + // When checking against Sub, we handle the condition codes GE, LT, GT, LE. + SmallVector OperandsToUpdate; + bool isSafe = false; + I = CmpInstr; + E = CmpInstr->getParent()->end(); + while (!isSafe && ++I != E) { + const MachineInstr &Instr = *I; + for (unsigned IO = 0, EO = Instr.getNumOperands(); !isSafe && IO != EO; ++IO) { + const MachineOperand &MO = Instr.getOperand(IO); + if (MO.isRegMask() && MO.clobbersPhysReg(Epiphany::NZCV)) { + isSafe = true; + break; + } + if (!MO.isReg() || MO.getReg() != Epiphany::NZCV) + continue; + if (MO.isDef()) { + isSafe = true; + break; + } + + EpiphanyCC::CondCodes CC; + switch(Instr.getOpcode()){ + case Epiphany::MOVCCrr: + case Epiphany::MOVCCss: + CC = (EpiphanyCC::CondCodes)Instr.getOperand(3).getImm(); + break; + case Epiphany::Bcc: + CC = (EpiphanyCC::CondCodes)Instr.getOperand(0).getImm(); + break; + } + + if (Sub) + switch (CC) { + default: + return false; + case EpiphanyCC::GTE: + case EpiphanyCC::LT: + case EpiphanyCC::GT: + case EpiphanyCC::LTE: + // If we have SUB(r1, r2) and CMP(r2, r1), the condition code based + // on CMP needs to be updated to be based on SUB. + // Push the condition code operands to OperandsToUpdate. + // If it is safe to remove CmpInstr, the condition code of these + // operands will be modified. + if (SrcReg2 != 0 && Sub->getOperand(1).getReg() == SrcReg2 && + Sub->getOperand(2).getReg() == SrcReg) + OperandsToUpdate.push_back(&((*I).getOperand(IO-1))); + break; + } + else + switch (CC) { + default: + isSafe = true; + break; + //case EpiphanyCC::VS: + //case EpiphanyCC::VC: + case EpiphanyCC::GTE: + case EpiphanyCC::LT: + case EpiphanyCC::GT: + case EpiphanyCC::LTE: + return false; + } + } + } + + // If the candidate is Sub, we may exit the loop at end of the basic block. + // In that case, it is still safe to remove CmpInstr. + if (!isSafe && !Sub) + return false; + + // Toggle the optional operand to CPSR. + //MI->getOperand(5).setReg(Epiphany::NZCV); + //MI->getOperand(5).setIsDef(true); + CmpInstr->eraseFromParent(); + + // Modify the condition code of operands in OperandsToUpdate. + // Since we have SUB(r1, r2) and CMP(r2, r1), the condition code needs to + // be changed from r2 > r1 to r1 < r2, from r2 < r1 to r1 > r2, etc. + for (unsigned i = 0; i < OperandsToUpdate.size(); i++) { + EpiphanyCC::CondCodes CC = (EpiphanyCC::CondCodes)OperandsToUpdate[i]->getImm(); + EpiphanyCC::CondCodes NewCC; + switch(CC) { + default: break; + case EpiphanyCC::GTE: NewCC = EpiphanyCC::LTE; break; + case EpiphanyCC::LT: NewCC = EpiphanyCC::GT; break; + case EpiphanyCC::GT: NewCC = EpiphanyCC::LT; break; + case EpiphanyCC::LTE: NewCC = EpiphanyCC::GT; break; + } + OperandsToUpdate[i]->setImm(NewCC); + } + return true; + } + } + + return false; +} + +/// Does the Opcode represent a conditional branch that we can remove and re-add +/// at the end of a basic block? +static bool isCondBranch(unsigned Opc) { + return Opc == Epiphany::Bcc; +} + +/// Takes apart a given conditional branch MachineInstr (see isCondBranch), +/// setting TBB to the destination basic block and populating the Cond vector +/// with data necessary to recreate the conditional branch at a later +/// date. First element will be the opcode, and subsequent ones define the +/// conditions being branched on in an instruction-specific manner. +static void classifyCondBranch(MachineInstr *I, MachineBasicBlock *&TBB, + SmallVectorImpl &Cond) { + switch(I->getOpcode()) { + case Epiphany::Bcc: + // These instructions just have one predicate operand in position 0 (either + // a condition code or a register being compared). + Cond.push_back(MachineOperand::CreateImm(I->getOpcode())); + Cond.push_back(I->getOperand(0)); + TBB = I->getOperand(1).getMBB(); + return; + default: + llvm_unreachable("Unknown conditional branch to classify"); + } +} + + +bool +EpiphanyInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const { + // If the block has no terminators, it just falls into the block after it. + MachineBasicBlock::iterator I = MBB.end(); + if (I == MBB.begin()) + return false; + --I; + while (I->isDebugValue()) { + if (I == MBB.begin()) + return false; + --I; + } + if (!isUnpredicatedTerminator(I)) + return false; + + // Get the last instruction in the block. + MachineInstr *LastInst = I; + + // If there is only one terminator instruction, process it. + unsigned LastOpc = LastInst->getOpcode(); + if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) { + if (LastOpc == Epiphany::Bimm) { + TBB = LastInst->getOperand(0).getMBB(); + return false; + } + if (isCondBranch(LastOpc)) { + classifyCondBranch(LastInst, TBB, Cond); + return false; + } + return true; // Can't handle indirect branch. + } + + // Get the instruction before it if it is a terminator. + MachineInstr *SecondLastInst = I; + unsigned SecondLastOpc = SecondLastInst->getOpcode(); + + // If AllowModify is true and the block ends with two or more unconditional + // branches, delete all but the first unconditional branch. + if (AllowModify && LastOpc == Epiphany::Bimm) { + while (SecondLastOpc == Epiphany::Bimm) { + LastInst->eraseFromParent(); + LastInst = SecondLastInst; + LastOpc = LastInst->getOpcode(); + if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) { + // Return now the only terminator is an unconditional branch. + TBB = LastInst->getOperand(0).getMBB(); + return false; + } else { + SecondLastInst = I; + SecondLastOpc = SecondLastInst->getOpcode(); + } + } + } + + // If there are three terminators, we don't know what sort of block this is. + if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(--I)) + return true; + + // If the block ends with a B and a Bcc, handle it. + if (LastOpc == Epiphany::Bimm) { + if (SecondLastOpc == Epiphany::Bcc) { + TBB = SecondLastInst->getOperand(1).getMBB(); + Cond.push_back(MachineOperand::CreateImm(Epiphany::Bcc)); + Cond.push_back(SecondLastInst->getOperand(0)); + FBB = LastInst->getOperand(0).getMBB(); + return false; + } else if (isCondBranch(SecondLastOpc)) { + classifyCondBranch(SecondLastInst, TBB, Cond); + FBB = LastInst->getOperand(0).getMBB(); + return false; + } + } + + // If the block ends with two unconditional branches, handle it. The second + // one is not executed, so remove it. + if (SecondLastOpc == Epiphany::Bimm && LastOpc == Epiphany::Bimm) { + TBB = SecondLastInst->getOperand(0).getMBB(); + I = LastInst; + if (AllowModify) + I->eraseFromParent(); + return false; + } + + // Otherwise, can't handle this. + return true; +} + +unsigned +EpiphanyInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl &Cond, + DebugLoc DL) const { + if (FBB == 0 && Cond.empty()) { + BuildMI(&MBB, DL, get(Epiphany::Bimm)).addMBB(TBB); + return 1; + } else if (FBB == 0) { + MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm())); + for (int i = 1, e = Cond.size(); i != e; ++i) + MIB.addOperand(Cond[i]); + MIB.addMBB(TBB); + return 1; + } + + MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm())); + for (int i = 1, e = Cond.size(); i != e; ++i) + MIB.addOperand(Cond[i]); + MIB.addMBB(TBB); + + BuildMI(&MBB, DL, get(Epiphany::Bimm)).addMBB(FBB); + return 2; +} + +unsigned EpiphanyInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator I = MBB.end(); + if (I == MBB.begin()) return 0; + --I; + while (I->isDebugValue()) { + if (I == MBB.begin()) + return 0; + --I; + } + if (I->getOpcode() != Epiphany::Bimm && !isCondBranch(I->getOpcode())) + return 0; + + // Remove the branch. + I->eraseFromParent(); + + I = MBB.end(); + + if (I == MBB.begin()) return 1; + --I; + if (!isCondBranch(I->getOpcode())) + return 1; + + // Remove the branch. + I->eraseFromParent(); + return 2; +} + +bool +EpiphanyInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MBBI) const { + return false; +} + +void +EpiphanyInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, + int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL = MBB.findDebugLoc(MBBI); + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + unsigned Align = MFI.getObjectAlignment(FrameIdx); + + MachineMemOperand *MMO + = MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(FrameIdx), + MachineMemOperand::MOStore, + MFI.getObjectSize(FrameIdx), + Align); + + unsigned StoreOp = 0; + if (RC->hasType(MVT::i64) || RC->hasType(MVT::i32)) { + switch(RC->getSize()) { + case 4: StoreOp = Epiphany::LS32_STR; break; + //case 8: StoreOp = Epiphany::LS64_STR; break; + default: + llvm_unreachable("Unknown size for regclass"); + } + } else { + assert((RC->hasType(MVT::f32) || RC->hasType(MVT::f64)) + && "Expected integer or floating type for store"); + switch (RC->getSize()) { + case 4: StoreOp = Epiphany::LSFP32_STR; break; + //case 8: StoreOp = Epiphany::LSFP64_STR; break; + default: + llvm_unreachable("Unknown size for regclass"); + } + } + + MachineInstrBuilder NewMI = BuildMI(MBB, MBBI, DL, get(StoreOp)); + NewMI.addReg(SrcReg, getKillRegState(isKill)) + .addFrameIndex(FrameIdx) + .addImm(0) + .addMemOperand(MMO); + +} + +void +EpiphanyInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL = MBB.findDebugLoc(MBBI); + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + unsigned Align = MFI.getObjectAlignment(FrameIdx); + + MachineMemOperand *MMO + = MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(FrameIdx), + MachineMemOperand::MOLoad, + MFI.getObjectSize(FrameIdx), + Align); + + unsigned LoadOp = 0; + if (RC->hasType(MVT::i64) || RC->hasType(MVT::i32)) { + switch(RC->getSize()) { + case 4: LoadOp = Epiphany::LS32_LDR; break; + //case 8: LoadOp = Epiphany::LS64_LDR; break; + default: + llvm_unreachable("Unknown size for regclass"); + } + } else { + assert((RC->hasType(MVT::f32) || RC->hasType(MVT::f64)) + && "Expected integer or floating type for store"); + switch (RC->getSize()) { + case 4: LoadOp = Epiphany::LSFP32_LDR; break; + //case 8: LoadOp = Epiphany::LSFP64_LDR; break; + default: + llvm_unreachable("Unknown size for regclass"); + } + } + + MachineInstrBuilder NewMI = BuildMI(MBB, MBBI, DL, get(LoadOp), DestReg); + NewMI.addFrameIndex(FrameIdx) + .addImm(0) + .addMemOperand(MMO); +} + +unsigned EpiphanyInstrInfo::estimateRSStackLimit(MachineFunction &MF) const { + unsigned Limit = (1 << 16) - 1; + for (MachineFunction::iterator BB = MF.begin(),E = MF.end(); BB != E; ++BB) { + for (MachineBasicBlock::iterator I = BB->begin(), E = BB->end(); + I != E; ++I) { + for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { + if (!I->getOperand(i).isFI()) continue; + + // When using ADDwwi_lsl0_s to get the address of a stack object, 0x3FF + // is the largest offset guaranteed to fit in the immediate offset. + if (I->getOpcode() == Epiphany::ADDri) { + Limit = std::min(Limit, 0x3FFu); + break; + } + + int AccessScale, MinOffset, MaxOffset; + getAddressConstraints(*I, AccessScale, MinOffset, MaxOffset); + Limit = std::min(Limit, static_cast(MaxOffset)); + + break; // At most one FI per instruction + } + } + } + + return Limit; +} +void EpiphanyInstrInfo::getAddressConstraints(const MachineInstr &MI, + int &AccessScale, int &MinOffset, + int &MaxOffset) const { + switch (MI.getOpcode()) { + default: llvm_unreachable("Unkown load/store kind"); + case TargetOpcode::DBG_VALUE: + AccessScale = 1; + MinOffset = INT_MIN; + MaxOffset = INT_MAX; + return; + case Epiphany::LS8_LDR: case Epiphany::LS8_STR: + AccessScale = 1; + MinOffset = 0; + MaxOffset = 0x7FF; + return; + case Epiphany::LS16_LDR: case Epiphany::LS16_STR: + AccessScale = 2; + MinOffset = 0; + MaxOffset = 0x7FF * AccessScale; + return; + case Epiphany::LS32_LDR: case Epiphany::LS32_STR: + case Epiphany::LSFP32_LDR: case Epiphany::LSFP32_STR: + AccessScale = 4; + MinOffset = 0; + MaxOffset = 0x7FF * AccessScale; + return; + //case Epiphany::LSFP64_LDR: case Epiphany::LSFP64_STR: + // AccessScale = 8; + // MinOffset = 0; + // MaxOffset = 0x7FF * AccessScale; + // return; + } +} + +unsigned EpiphanyInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { + const MCInstrDesc &MCID = MI.getDesc(); + const MachineBasicBlock &MBB = *MI.getParent(); + const MachineFunction &MF = *MBB.getParent(); + const MCAsmInfo &MAI = *MF.getTarget().getMCAsmInfo(); + + if (MCID.getSize()) + return MCID.getSize(); + + if (MI.getOpcode() == Epiphany::INLINEASM) + return getInlineAsmLength(MI.getOperand(0).getSymbolName(), MAI); + + if (MI.isLabel()) + return 0; + + switch (MI.getOpcode()) { + case TargetOpcode::BUNDLE: + return getInstBundleLength(MI); + case TargetOpcode::IMPLICIT_DEF: + case TargetOpcode::KILL: + case TargetOpcode::PROLOG_LABEL: + case TargetOpcode::EH_LABEL: + case TargetOpcode::DBG_VALUE: + return 0; + default: + llvm_unreachable("Unknown instruction class"); + } +} + +unsigned EpiphanyInstrInfo::getInstBundleLength(const MachineInstr &MI) const { + unsigned Size = 0; + MachineBasicBlock::const_instr_iterator I = MI; + MachineBasicBlock::const_instr_iterator E = MI.getParent()->instr_end(); + while (++I != E && I->isInsideBundle()) { + assert(!I->isBundle() && "No nested bundle!"); + Size += getInstSizeInBytes(*I); + } + return Size; +} + +bool llvm::rewriteA64FrameIndex(MachineInstr &MI, unsigned FrameRegIdx, + unsigned FrameReg, int &Offset, + const EpiphanyInstrInfo &TII) { + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + + MFI.getObjectOffset(FrameRegIdx); + llvm_unreachable("Unimplemented rewriteFrameIndex"); +} + +void llvm::EPIPHemitRegUpdate(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + DebugLoc dl, const TargetInstrInfo &TII, + unsigned DstReg, unsigned SrcReg, unsigned ScratchReg, + int64_t NumBytes, MachineInstr::MIFlag MIFlags) { + if (NumBytes == 0 && DstReg == SrcReg) + return; + else if (abs(NumBytes) & ~0x3FF) { // 11bit signed = 10b unsigned + // Generically, we have to materialize the offset into a temporary register + // and subtract it. There are a couple of ways this could be done, for now + // we'll use a movz/movk or movn/movk sequence. + uint64_t Bits = static_cast(abs(NumBytes)); + BuildMI(MBB, MBBI, dl, TII.get(Epiphany::MOVri), ScratchReg) + .addImm(0xffff & Bits).setMIFlags(MIFlags); + + Bits >>= 16; + if (Bits & 0xffff) { + BuildMI(MBB, MBBI, dl, TII.get(Epiphany::MOVTri), ScratchReg) + .addImm(0xffff & Bits).setMIFlags(MIFlags); + } + + //HACK since we have only 32b at most this needs only a mov + movt + // ADD DST, SRC, xTMP (, lsl #0) + unsigned AddOp = NumBytes > 0 ? Epiphany::ADDrr : Epiphany::SUBrr; + BuildMI(MBB, MBBI, dl, TII.get(AddOp), DstReg) + .addReg(SrcReg, RegState::Kill) + .addReg(ScratchReg, RegState::Kill) + .addImm(0) + .setMIFlag(MIFlags); + return; + } + + // Now we know that the adjustment can be done in at most two add/sub + // (immediate) instructions, which is always more efficient than a + // literal-pool load, or even a hypothetical movz/movk/add sequence + + // Decide whether we're doing addition or subtraction + unsigned LowOp, HighOp; + if (NumBytes >= 0) { + LowOp = Epiphany::ADDri; + //HighOp = Epiphany::ADDwwi_lsl12_s; + } else { + LowOp = Epiphany::SUBri; + //HighOp = Epiphany::SUBwwi_lsl12_s; + NumBytes = abs(NumBytes); + } + + // If we're here, at the very least a move needs to be produced, which just + // happens to be materializable by an ADD. + if ((NumBytes & 0x3FF) || NumBytes == 0) { + BuildMI(MBB, MBBI, dl, TII.get(LowOp), DstReg) + .addReg(SrcReg, RegState::Kill) + .addImm(NumBytes & 0x3FF) + .setMIFlag(MIFlags); + + // Next update should use the register we've just defined. + SrcReg = DstReg; + } + + if (NumBytes & 0xfff000) { + llvm_unreachable("oh fuck.... hi bits reg update"); + BuildMI(MBB, MBBI, dl, TII.get(HighOp), DstReg) + .addReg(SrcReg, RegState::Kill) + .addImm(NumBytes >> 12) + .setMIFlag(MIFlags); + } +} + +void llvm::EPIPHemitSPUpdate(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + DebugLoc dl, const TargetInstrInfo &TII, + unsigned ScratchReg, int64_t NumBytes, + MachineInstr::MIFlag MIFlags) { + EPIPHemitRegUpdate(MBB, MI, dl, TII, Epiphany::SP, Epiphany::SP, Epiphany::R63, + NumBytes, MIFlags); +} diff --git a/EpiphanyInstrInfo.h b/EpiphanyInstrInfo.h new file mode 100644 index 0000000..14dc274 --- /dev/null +++ b/EpiphanyInstrInfo.h @@ -0,0 +1,120 @@ +//===- EpiphanyInstrInfo.h - Epiphany Instruction Information -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Epiphany implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_EPIPHANYINSTRINFO_H +#define LLVM_TARGET_EPIPHANYINSTRINFO_H + +#include "llvm/Target/TargetInstrInfo.h" +#include "EpiphanyRegisterInfo.h" + +#define GET_INSTRINFO_HEADER +#include "EpiphanyGenInstrInfo.inc" + +namespace llvm { + +class EpiphanySubtarget; + +class EpiphanyInstrInfo : public EpiphanyGenInstrInfo { + const EpiphanyRegisterInfo RI; + const EpiphanySubtarget &Subtarget; +public: + explicit EpiphanyInstrInfo(const EpiphanySubtarget &TM); + + /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As + /// such, whenever a client has an instance of instruction info, it should + /// always be able to get register info as well (through this method). + /// + const TargetRegisterInfo &getRegisterInfo() const { return RI; } + + const EpiphanySubtarget &getSubTarget() const { return Subtarget; } + + void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const; + + MachineInstr *emitFrameIndexDebugValue(MachineFunction &MF, int FrameIx, + uint64_t Offset, const MDNode *MDPtr, + DebugLoc DL) const; + + void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + + bool analyzeCompare(const MachineInstr *MI, unsigned &SrcReg, + unsigned &SrcReg2, + int &CmpMask, int &CmpValue) const; + + bool optimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, + unsigned SrcReg2, int CmpMask, int CmpValue, + const MachineRegisterInfo *MRI) const; + + + bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify = false) const; + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl &Cond, + DebugLoc DL) const; + unsigned RemoveBranch(MachineBasicBlock &MBB) const; + + bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const; + + /// Look through the instructions in this function and work out the largest + /// the stack frame can be while maintaining the ability to address local + /// slots with no complexities. + unsigned estimateRSStackLimit(MachineFunction &MF) const; + + /// getAddressConstraints - For loads and stores (and PRFMs) taking an + /// immediate offset, this function determines the constraints required for + /// the immediate. It must satisfy: + /// + MinOffset <= imm <= MaxOffset + /// + imm % OffsetScale == 0 + void getAddressConstraints(const MachineInstr &MI, int &AccessScale, + int &MinOffset, int &MaxOffset) const; + + + unsigned getInstSizeInBytes(const MachineInstr &MI) const; + + unsigned getInstBundleLength(const MachineInstr &MI) const; + +}; + +bool rewriteA64FrameIndex(MachineInstr &MI, unsigned FrameRegIdx, + unsigned FrameReg, int &Offset, + const EpiphanyInstrInfo &TII); + + +void EPIPHemitRegUpdate(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + DebugLoc dl, const TargetInstrInfo &TII, + unsigned DstReg, unsigned SrcReg, unsigned ScratchReg, + int64_t NumBytes, + MachineInstr::MIFlag MIFlags = MachineInstr::NoFlags); + +void EPIPHemitSPUpdate(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + DebugLoc dl, const TargetInstrInfo &TII, + unsigned ScratchReg, int64_t NumBytes, + MachineInstr::MIFlag MIFlags = MachineInstr::NoFlags); + +} + +#endif diff --git a/EpiphanyInstrInfo.td b/EpiphanyInstrInfo.td new file mode 100644 index 0000000..2b09f86 --- /dev/null +++ b/EpiphanyInstrInfo.td @@ -0,0 +1,612 @@ +//===----- EpiphanyInstrInfo.td - Epiphany Instruction Info ----*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the Epiphany scalar instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +include "EpiphanyInstrFormats.td" + +//===----------------------------------------------------------------------===// +// Target-specific ISD nodes and profiles +//===----------------------------------------------------------------------===// + +//(outs rd), ins (rd, rn, rm, is_sub_flag) +def SDT_fm_a_s : SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, SDTCisFP<0>, SDTCisVT<4, i32>]>; +def EPIfmas : SDNode<"EpiphanyISD::FM_A_S", SDT_fm_a_s>; + +def SDT_A64ret : SDTypeProfile<0, 0, []>; +def A64ret : SDNode<"EpiphanyISD::Ret", SDT_A64ret, [SDNPHasChain, + SDNPOptInGlue, + SDNPVariadic]>; + +// (ins NZCV, Condition, Dest) +def SDT_A64br_cc : SDTypeProfile<0, 3, [SDTCisVT<0, i32>]>; +def A64br_cc : SDNode<"EpiphanyISD::BR_CC", SDT_A64br_cc, [SDNPHasChain]>; + +// (outs Result), (ins NZCV, IfTrue, IfFalse, Condition) +def SDT_A64select_cc : SDTypeProfile<1, 4, [SDTCisVT<1, i32>, + SDTCisSameAs<0, 2>, + SDTCisSameAs<2, 3>]>; +def A64select_cc : SDNode<"EpiphanyISD::SELECT_CC", SDT_A64select_cc>; + +// (outs NZCV), (ins LHS, RHS, Condition) +def SDT_A64setcc : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, + SDTCisSameAs<1, 2>]>; +def A64setcc : SDNode<"EpiphanyISD::SETCC", SDT_A64setcc>; + + +// (outs GPR32), (ins) +//def A64threadpointer : SDNode<"EpiphanyISD::THREAD_POINTER", SDTPtrLeaf>; + +// A64 compares don't care about the cond really (they set all flags) so a +// simple binary operator is useful. +def A64cmp : PatFrag<(ops node:$lhs, node:$rhs), (A64setcc node:$lhs, node:$rhs, cond)>; + + + +// There are two layers of indirection here, driven by the following +// considerations. +// + TableGen does not know CodeModel or Reloc so that decision should be +// made for a variable/address at ISelLowering. +// + The output of ISelLowering should be selectable (hence the Wrapper, +// rather than a bare target opcode) +def SDTEpiphanyWrapper : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, + SDTCisSameAs<1, 2>, + SDTCisVT<3, i32>, + SDTCisPtrTy<0>]>; + +def A64WrapperSmall : SDNode<"EpiphanyISD::WrapperSmall", SDTEpiphanyWrapper>; + + +//===----------------------------------------------------------------------===// +// Call sequence pseudo-instructions +//===----------------------------------------------------------------------===// + + +def SDT_EpiphanyCall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>; +def EpiphanyCall : SDNode<"EpiphanyISD::Call", SDT_EpiphanyCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; + +def SDT_EpiphanyCallSeqStart : SDCallSeqStart<[ SDTCisPtrTy<0> ]>; +def Epiphanycallseq_start : SDNode<"ISD::CALLSEQ_START", SDT_EpiphanyCallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; + +def SDT_EpiphanyCallSeqEnd : SDCallSeqEnd<[ SDTCisPtrTy<0>, SDTCisPtrTy<1> ]>; +def Epiphanycallseq_end : SDNode<"ISD::CALLSEQ_END", SDT_EpiphanyCallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; + + + +// These pseudo-instructions have special semantics by virtue of being passed to +// the InstrInfo constructor. CALLSEQ_START/CALLSEQ_END are produced by +// LowerCall to (in our case) tell the back-end about stack adjustments for +// arguments passed on the stack. Here we select those markers to +// pseudo-instructions which explicitly set the stack, and finally in the +// RegisterInfo we convert them to a true stack adjustment. +let Defs = [SP], Uses = [SP] in { + def ADJCALLSTACKDOWN : PseudoInst<(outs), (ins i32imm:$amt), + [(Epiphanycallseq_start timm:$amt)]>; + + def ADJCALLSTACKUP : PseudoInst<(outs), (ins i32imm:$amt1, i32imm:$amt2), + [(Epiphanycallseq_end timm:$amt1, timm:$amt2)]>; +} + +//===----------------------------------------------------------------------===// +// Logical (register) instructions +//===----------------------------------------------------------------------===// +let Defs = [NZCV] in { + def ANDrr : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, GPR32:$Rm),"and\t$Rd, $Rn, $Rm",[(set GPR32:$Rd, (and GPR32:$Rn, GPR32:$Rm))],NoItinerary>; + def ORRrr : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, GPR32:$Rm),"orr\t$Rd, $Rn, $Rm",[(set GPR32:$Rd, (or GPR32:$Rn, GPR32:$Rm))],NoItinerary>; + def EORrr : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, GPR32:$Rm),"eor\t$Rd, $Rn, $Rm",[(set GPR32:$Rd, (xor GPR32:$Rn, GPR32:$Rm))],NoItinerary>; +} +//===----------------------------------------------------------------------===// +// Add-subtract (immediate) instructions +//===----------------------------------------------------------------------===// + +def neg_XFORM : SDNodeXFormgetTargetConstant(-N->getZExtValue(), MVT::i32); +}]>; + + + let PrintMethod = "printAddSubImmOperand" in { + def addsubimm_i32_normal : Operand, ImmLeaf= -1024 && Imm <= 1023; }]>; + def addsubimm_i32_special_minus : Operand, ImmLeaf; + } + +let Defs = [NZCV] in { +def ADDri : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, addsubimm_i32_normal:$Imm12),"add\t$Rd, $Rn, $Imm12",[/*(set GPR32:$Rd, (addc GPR32:$Rn, imm:$Imm12))*/],NoItinerary>; +def SUBri : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, addsubimm_i32_normal:$Imm12),"sub\t$Rd, $Rn, $Imm12",[/*(set GPR32:$Rd, (subc GPR32:$Rn, imm:$Imm12))*/],NoItinerary>; + + let isCompare = 1 in{ + def SUBri_cmp : EP3INST<(outs),(ins GPR32:$Rn, addsubimm_i32_normal:$Imm12),"cmp\tR63, $Rn, $Imm12",[/*(set NZCV, (A64setcc GPR32:$Rn, imm:$Imm12, cond))*/],NoItinerary>; + } +} + +// special case: add +1024 -> sub -1024 and sub +1024 -> add -1024 +def : Pat<(add GPR32:$Rn, addsubimm_i32_special_minus:$Imm12),(SUBri GPR32:$Rn, addsubimm_i32_special_minus:$Imm12)>; +def : Pat<(sub GPR32:$Rn, addsubimm_i32_special_minus:$Imm12),(ADDri GPR32:$Rn, addsubimm_i32_special_minus:$Imm12)>; + +def : Pat<(add GPR32:$Rn, addsubimm_i32_normal:$Imm12),(ADDri GPR32:$Rn, addsubimm_i32_normal:$Imm12)>; +def : Pat<(addc GPR32:$Rn, addsubimm_i32_normal:$Imm12),(ADDri GPR32:$Rn, addsubimm_i32_normal:$Imm12)>; + + +def : Pat<(sub GPR32:$Rn, addsubimm_i32_normal:$Imm12),(SUBri GPR32:$Rn, addsubimm_i32_normal:$Imm12)>; +def : Pat<(subc GPR32:$Rn, addsubimm_i32_normal:$Imm12),(SUBri GPR32:$Rn, addsubimm_i32_normal:$Imm12)>; + +// def : Pat<(A64setcc GPR32:$Rn, addsubimm_i32_normal:$Imm12, cond),(ADDri_cmp GPR32:$Rn, addsubimm_i32_normal:$Imm12)>; +def : Pat<(A64setcc GPR32:$Rn, addsubimm_i32_normal:$Imm12, cond),(SUBri_cmp GPR32:$Rn, addsubimm_i32_normal:$Imm12)>; + +//===----------------------------------------------------------------------===// +// Add-subtract ( register) instructions +//===----------------------------------------------------------------------===// + +let Defs = [NZCV] in { +def ADDrr : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, GPR32:$Rm),"add\t$Rd, $Rn, $Rm",[(set GPR32:$Rd, (addc GPR32:$Rn, (i32 GPR32:$Rm)))],NoItinerary>; +def SUBrr : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, GPR32:$Rm),"sub\t$Rd, $Rn, $Rm",[(set GPR32:$Rd, (subc GPR32:$Rn, (i32 GPR32:$Rm)))],NoItinerary>; + let isCompare = 1 in { + def CMPrr : EP3INST<(outs),(ins GPR32:$Rn, GPR32:$Rm),"cmp\tR63, $Rn, $Rm",[(set NZCV, (A64cmp GPR32:$Rn, (i32 GPR32:$Rm)))],NoItinerary>; + } + // let Rd = 0b11111, isCompare = 1 in { + // defm CMPw : addsub_exts<0b0, 0b1, 0b1, "cmp\t", SetNZCV, (outs), GPR32>; + // } +} + +def : Pat<(add GPR32:$Rn, (i32 GPR32:$Rm)), (ADDrr GPR32:$Rn, GPR32:$Rm)>; +def : Pat<(sub GPR32:$Rn, (i32 GPR32:$Rm)), (SUBrr GPR32:$Rn, GPR32:$Rm)>; +def : Pat<(A64cmp GPR32:$Rn, (i32 GPR32:$Rm)), (CMPrr GPR32:$Rn, GPR32:$Rm)>; + +//===----------------------------------------------------------------------===// +// Data Processing (1 source) instructions +//===----------------------------------------------------------------------===// +def REVr : EP2INST<(outs GPR32:$Rd),(ins GPR32:$Rn),"rev\t$Rd, $Rn",[(set GPR32:$Rd, (bswap GPR32:$Rn))],NoItinerary>; + +//===----------------------------------------------------------------------===// +// Data Processing (2 sources) instructions +//===----------------------------------------------------------------------===// + +def shifts_5bit : Operand, ImmLeaf= 0 && Imm <= 31 }]>; + +let Defs = [NZCV] in { + def LSLri : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, shifts_5bit:$UImm5),"lsl\t$Rd, $Rn, $UImm5",[(set GPR32:$Rd, (shl GPR32:$Rn, (i32 imm:$UImm5)) )],NoItinerary>; + def LSRri : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, shifts_5bit:$UImm5),"lsr\t$Rd, $Rn, $UImm5",[(set GPR32:$Rd, (srl GPR32:$Rn, (i32 imm:$UImm5)) )],NoItinerary>; + def ASRri : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, shifts_5bit:$UImm5),"asr\t$Rd, $Rn, $UImm5",[(set GPR32:$Rd, (sra GPR32:$Rn, (i32 imm:$UImm5)) )],NoItinerary>; + + def LSLrr : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, GPR32:$Rm),"lsl\t$Rd, $Rn, $Rm",[(set GPR32:$Rd, (shl GPR32:$Rn, GPR32:$Rm))],NoItinerary>; + def LSRrr : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, GPR32:$Rm),"lsr\t$Rd, $Rn, $Rm",[(set GPR32:$Rd, (srl GPR32:$Rn, GPR32:$Rm))],NoItinerary>; + def ASRrr : EP3INST<(outs GPR32:$Rd),(ins GPR32:$Rn, GPR32:$Rm),"asr\t$Rd, $Rn, $Rm",[(set GPR32:$Rd, (sra GPR32:$Rn, GPR32:$Rm))],NoItinerary>; +} +//===----------------------------------------------------------------------===// +// Floating-point compare instructions +//===----------------------------------------------------------------------===// +let Defs = [NZCV] in { + def FCMPss : EP3INST<(outs), (ins FPR32:$Rn, FPR32:$Rm), "fcmp\t$Rn, $Rm", [(set NZCV, (A64cmp (f32 FPR32:$Rn), FPR32:$Rm))], NoItinerary> {} + + let isCommutable = 1 in { + def FMUL_ss : EP3INST<(outs FPR32:$Rd),(ins FPR32:$Rn, FPR32:$Rm),"fmul\t$Rd, $Rn, $Rm",[(set (f32 FPR32:$Rd), (fmul FPR32:$Rn, FPR32:$Rm))],NoItinerary>; + def FADD_ss : EP3INST<(outs FPR32:$Rd),(ins FPR32:$Rn, FPR32:$Rm),"fadd\t$Rd, $Rn, $Rm",[(set (f32 FPR32:$Rd), (fadd FPR32:$Rn, FPR32:$Rm))],NoItinerary>; + } + def FSUB_ss : EP3INST<(outs FPR32:$Rd),(ins FPR32:$Rn, FPR32:$Rm),"fsub\t$Rd, $Rn, $Rm",[(set (f32 FPR32:$Rd), (fsub FPR32:$Rn, FPR32:$Rm))],NoItinerary>; + + let Constraints = "$Rd = $Ra" in { + def FMADDsss : EP3INST<(outs FPR32:$Rd),(ins FPR32:$Ra, FPR32:$Rn, FPR32:$Rm),"fmadd\t$Rd, $Rn, $Rm",[/*(set FPR32:$Rd, (fadd FPR32:$Ra, (fmul FPR32:$Rn, FPR32:$Rm)))*/],NoItinerary>; + def FMSUBsss : EP3INST<(outs FPR32:$Rd),(ins FPR32:$Ra, FPR32:$Rn, FPR32:$Rm),"fmsub\t$Rd, $Rn, $Rm",[/*(set FPR32:$Rd, (fsub FPR32:$Ra, (fmul FPR32:$Rn, FPR32:$Rm)))*/],NoItinerary>; + } +} + + def : Pat<(EPIfmas FPR32:$Rd, FPR32:$Rn, FPR32:$Rm, 0),(FMADDsss FPR32:$Rd, FPR32:$Rn, FPR32:$Rm)>; + def : Pat<(EPIfmas FPR32:$Rd, FPR32:$Rn, FPR32:$Rm, 1),(FMSUBsss FPR32:$Rd, FPR32:$Rn, FPR32:$Rm)>; + +let Defs = [NZCV] in { + //===----------------------------------------------------------------------===// + // Floating-point <-> integer conversion instructions + //===----------------------------------------------------------------------===// + def FIXrs : EP3INST<(outs GPR32:$Rd),(ins FPR32:$Rn),"FIX\t$Rd, $Rn",[(set (i32 GPR32:$Rd), (i32 (fp_to_sint FPR32:$Rn)) )],NoItinerary>; + def FLOATsr : EP3INST<(outs FPR32:$Rd),(ins GPR32:$Rn),"FLOAT\t$Rd, $Rn",[(set (f32 FPR32:$Rd), (f32 (sint_to_fp GPR32:$Rn)) )],NoItinerary>; + def FABSss : EP3INST<(outs FPR32:$Rd), (ins FPR32:$Rn), "FABS\t$Rd, $Rn",[(set FPR32:$Rd, (fabs FPR32:$Rn))],NoItinerary>; +} +//===----------------------------------------------------------------------===// +// Move wide (immediate) instructions +//===----------------------------------------------------------------------===// + +def LO16 : SDNodeXFormgetZExtValue() & 0xFFFF); +}]>; + +def HI16 : SDNodeXFormgetZExtValue() >> 16) & 0xFFFF); +}]>; + +def immZExt16 : PatLeaf<(imm), [{ + return (uint32_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); +}], LO16>; + +def immLow16Zero : PatLeaf<(imm), [{ + int64_t Val = N->getSExtValue(); + return isInt<32>(Val) && !(Val & 0xffff); +}]>; + +def fmov32_operand : Operand, PatLeaf<(f32 fpimm), [{ return EpiphanyImms::isFPImm(N->getValueAPF()); }]> { let PrintMethod = "printFPImmOperand";} + + +let isMoveImm = 1, isAsCheapAsAMove = 1, hasSideEffects = 0 in { + let Constraints = "$src = $rt" in { + def MOVTri : EP2INST<(outs GPR32:$rt), (ins GPR32:$src, i32imm:$imm16),"movt\t$rt, $imm16",[(set GPR32:$rt, (or (and GPR32:$src, 0xffff), immLow16Zero:$imm16))],NoItinerary>; + def MOVTri_nopat : EP2INST<(outs GPR32:$rt), (ins GPR32:$src, i32imm:$imm16),"movt\t$rt, $imm16",[],NoItinerary>; + + def MOVTri_nopat_f : EP2INST<(outs FPR32:$rt), (ins FPR32:$src, fmov32_operand:$imm16),"movt\t$rt, $imm16",[],NoItinerary>; + } + def MOVTri_nopat_nodstsrc : EP2INST<(outs GPR32:$rt), (ins i32imm:$imm16),"movt\t$rt, $imm16",[],NoItinerary>; + + def MOVri : EP2INST<(outs GPR32:$rt), (ins i32imm:$imm16), "mov\t$rt, $imm16", [(set GPR32:$rt, immZExt16:$imm16)], NoItinerary>; + def MOVri_nopat : EP2INST<(outs GPR32:$rt),(ins i32imm:$imm16), "mov\t$rt, $imm16", [], NoItinerary>; + + def MOVri_nopat_f : EP2INST<(outs FPR32:$rt),(ins fmov32_operand:$imm16), "mov\t$rt, $imm16", [], NoItinerary>; + // def FMOVsi : EP2INST<(outs FPR32:$Rd), (ins fmov32_operand:$Imm8), "fmov\t$Rd, $Imm8", [], NoItinerary>; +} + +//Arbitrary immediates - unfortunately selecting those instead of the rr version fails, so -> code. +// def : Pat<(i32 imm:$imm), (MOVTri_nopat (MOVri_nopat (imm:$imm)),(imm:$imm))>; +// def : Pat<(f32 fpimm:$imm), (MOVTri_nopat_f (MOVri_nopat_f (fmov32_operand:$imm)),(fmov32_operand:$imm))>; +def : Pat<(or GPR32:$src, 0xffff0000), (MOVTri_nopat GPR32:$src, 0xffff)>; + + +class BitconvertPat : Pat<(DstVT (bitconvert (SrcVT SrcRC:$src))), (COPY_TO_REGCLASS SrcRC:$src, DstRC)>; +def : BitconvertPat; +def : BitconvertPat; + +//===----------------------------------------------------------------------===// +// MOVrr +//===----------------------------------------------------------------------===// +let hasSideEffects = 0 in{ +def MOVww : EP2INST<(outs GPR32:$Rd),(ins GPR32:$Rn),"mov\t$Rd, $Rn",[(set GPR32:$Rd, GPR32:$Rn)],NoItinerary>; +def MOVss : EP2INST<(outs FPR32:$Rd),(ins FPR32:$Rn),"mov\t$Rd, $Rn",[(set FPR32:$Rd, FPR32:$Rn)],NoItinerary>; +// def FMOVws : EP3INST<(outs GPR32:$Rd),(ins FPR32:$Rn),"fmov\t$Rd, $Rn",[(set (i32 GPR32:$Rd), (i32 (bitconvert (f32 FPR32:$Rn))) )],NoItinerary>; +// def FMOVsw : EP3INST<(outs FPR32:$Rd),(ins GPR32:$Rn),"fmov\t$Rd, $Rn",[(set (f32 FPR32:$Rd), (f32 (bitconvert (i32 GPR32:$Rn))) )],NoItinerary>; +} + + +def cond_code_op : Operand { + let PrintMethod = "printCondCodeOperand"; +} + +// ins true, false, cond -> we prepend a "mov $Rd, $Rfalse" and make sure that the output ends up in the same $Rd +// this will create a redundant move in case $Rd already happens to be $Rfalse... but we only know this after RA, so we'll fix this in a post-RA pass + let Uses = [NZCV], Constraints = "$Rd = $Rm" in { + def MOVCCrr : EP4INST<(outs GPR32:$Rd), (ins GPR32:$Rn, GPR32:$Rm, cond_code_op:$Cond), "mov$Cond\t$Rd, $Rn", [], NoItinerary>; + def MOVCCss : EP4INST<(outs FPR32:$Rd), (ins FPR32:$Rn, FPR32:$Rm, cond_code_op:$Cond), "mov$Cond\t$Rd, $Rn", [], NoItinerary>; + } + def : Pat<(A64select_cc NZCV, GPR32:$Rn, GPR32:$Rm, (i32 imm:$Cond)), (MOVCCrr GPR32:$Rn, (MOVww GPR32:$Rm), (i32 imm:$Cond))>; + def : Pat<(A64select_cc NZCV, FPR32:$Rn, FPR32:$Rm, (i32 imm:$Cond)), (MOVCCss FPR32:$Rn, (MOVss FPR32:$Rm), (i32 imm:$Cond))>; + + + //===----------------------------------------------------------------------===// +// Compare and branch (immediate) +//===----------------------------------------------------------------------===// +def bcc_bimm_target : Operand { + // This label is a 19-bit offset from PC, scaled by the instruction-width: 4. + let PrintMethod = "printLabelOperand<24, 2>"; + let OperandType = "OPERAND_PCREL"; +} + +//===----------------------------------------------------------------------===// +// Conditional branch (immediate) instructions +//===----------------------------------------------------------------------===// +def cond_code : Operand, ImmLeaf= 0 && Imm <= 15;}]> { let PrintMethod = "printCondCodeOperand";} + +def Bcc : EP2INST<(outs),(ins cond_code:$Cond, bcc_bimm_target:$Label),"b$Cond $Label",[(A64br_cc NZCV, (i32 imm:$Cond), bb:$Label)],NoItinerary>{ + let Uses = [NZCV]; + let isBranch = 1; + let isTerminator = 1; +} + +//===----------------------------------------------------------------------===// +// Unconditional branch (immediate) instructions +//===----------------------------------------------------------------------===// +def blimm_target : Operand { + // This label is a 26-bit offset from PC, scaled by the instruction-width: 4. + let PrintMethod = "printLabelOperand<24, 2>"; + let OperandType = "OPERAND_PCREL"; +} + +let isBranch = 1 in { + def Bimm : EP1INST<(outs), (ins bcc_bimm_target:$Label),"b\t$Label", [(br bb:$Label)],NoItinerary> { + let isTerminator = 1; + let isBarrier = 1; + } + + def BLimm : EP1INST<(outs), (ins blimm_target:$Label),"bl\t$Label", [(EpiphanyCall tglobaladdr:$Label)],NoItinerary> { + let isCall = 1; + let Defs = [LR]; + } +} + +def : Pat<(EpiphanyCall texternalsym:$Label), (BLimm texternalsym:$Label)>; + +//===----------------------------------------------------------------------===// +// Unconditional branch (register) instructions +//===----------------------------------------------------------------------===// +// Contains: BR, BLR, RET, ERET, DRP. + +// Most of the notional opcode fields in the A64I_Breg format are fixed in A64 +// at the moment. +class A64I_BregImpl patterns, InstrItinClass itin = NoItinerary> + : EP1INST { + let isBranch = 1; + let isIndirectBranch = 1; +} + +// Note that these are not marked isCall or isReturn because as far as LLVM is +// concerned they're not. "ret" is just another jump unless it has been selected +// by LLVM as the function's return. + +let isBranch = 1 in { + def JRx : A64I_BregImpl<(outs), (ins GPR32:$Rn),"jr\t$Rn", [(brind GPR32:$Rn)]> { + let isBarrier = 1; + let isTerminator = 1; + } + + def JALRx : A64I_BregImpl<(outs), (ins GPR32:$Rn),"jalr\t$Rn", [(EpiphanyCall GPR32:$Rn)]> { + let isBarrier = 0; + let isCall = 1; + let Defs = [LR]; + } + + def RETx : A64I_BregImpl<(outs), (ins GPR32:$Rn),"rts\t$Rn", []> { + let isBarrier = 1; + let isTerminator = 1; + let isReturn = 1; + } + + // Create a separate pseudo-instruction for codegen to use so that we don't + // flag LR as used in every function. It'll be restored before the RET by the + // epilogue if it's legitimately used. + def RET : A64PseudoExpand<(outs), (ins), [(A64ret)], (RETx (ops LR))> { + let isTerminator = 1; + let isBarrier = 1; + let isReturn = 1; + } +} + +def RETAlias : InstAlias<"rts", (RETx LR)>; + + +//===----------------------------------------------------------------------===// +// Address generation patterns +//===----------------------------------------------------------------------===// + +class ADRP_ADD : Pat<(A64WrapperSmall addrop:$Hi16, addrop:$Lo16, (i32 imm)), (MOVTri_nopat (MOVri_nopat (addrop:$Lo16)),(addrop:$Hi16))>; + +def : ADRP_ADD; +def : ADRP_ADD; +def : ADRP_ADD; +def : ADRP_ADD; + +//===----------------------------------------------------------------------===// +// LS stuff +//===----------------------------------------------------------------------===// + +def byte_simm11 : Operand, ComplexPattern"> { let PrintMethod = "printOffsetUImm11Operand<1>"; } +def hword_simm11 : Operand, ComplexPattern"> { let PrintMethod = "printOffsetUImm11Operand<2>"; } +def word_simm11 : Operand, ComplexPattern"> { let PrintMethod = "printOffsetUImm11Operand<4>"; } +def dword_simm11 : Operand, ComplexPattern"> { let PrintMethod = "printOffsetUImm11Operand<8>"; } + +//===------------------------------ +// 2.1 Regular instructions +//===------------------------------ + +multiclass A64I_LDRSTR_unsigned size, bit v, + bit high_opc, string asmsuffix, + RegisterClass GPR, Operand params> { + // Unsigned immediate + def _STR : EP3INST<(outs), (ins GPR:$Rt, GPR32:$Rn, params:$UImm11),"str" # asmsuffix # "\t$Rt, [$Rn, $UImm11]",[], NoItinerary> { + let mayStore = 1; + } + def : InstAlias<"str" # asmsuffix # " $Rt, [$Rn]", (!cast(prefix # "_STR") GPR:$Rt, GPR32:$Rn, 0)>; + + def _LDR : EP3INST<(outs GPR:$Rt), (ins GPR32:$Rn, params:$UImm11),"ldr" # asmsuffix # "\t$Rt, [$Rn, $UImm11]",[], NoItinerary> { + let mayLoad = 1; + } + def : InstAlias<"ldr" # asmsuffix # " $Rt, [$Rn]", (!cast(prefix # "_LDR") GPR:$Rt, GPR32:$Rn, 0)>; + + // Register offset (four of these: load/store and Wm/Xm). + def _RO_LDR : EP3INST<(outs GPR:$Rt),(ins GPR32:$Rn, GPR32:$Rm),"ldr" # asmsuffix # "\t$Rt, [$Rn, $Rm]",[], NoItinerary>{ + let mayLoad = 1; + } + def : InstAlias<"ldr" # asmsuffix # " $Rt, [$Rn, $Rm]", (!cast(prefix # "_RO_LDR") GPR:$Rt, GPR32:$Rn, GPR32:$Rm)>; + + + def _RO_STR : EP3INST<(outs), (ins GPR:$Rt, GPR32:$Rn, GPR32:$Rm),"str" # asmsuffix # "\t$Rt, [$Rn, $Rm]",[], NoItinerary>{ + let mayStore = 1; + } + def : InstAlias<"str" # asmsuffix # " $Rt, [$Rn, $Rm]", (!cast(prefix # "_RO_STR") GPR:$Rt, GPR32:$Rn, GPR32:$Rm)>; + + // Post-indexed + def _PostInd_STR : EP3INST<(outs GPR32:$Rn_wb),(ins GPR:$Rt, GPR32:$Rn, params:$SImm11),"str" # asmsuffix # "\t$Rt, [$Rn], $SImm11",[], NoItinerary> { + let Constraints = "$Rn = $Rn_wb"; + let mayStore = 1; + + // Decoder only needed for unpredictability checking (FIXME). + } + + def _PostInd_LDR : EP3INST<(outs GPR:$Rt, GPR32:$Rn_wb),(ins GPR32:$Rn, params:$SImm11),"ldr" # asmsuffix # "\t$Rt, [$Rn], $SImm11",[], NoItinerary> { + let mayLoad = 1; + let Constraints = "$Rn = $Rn_wb"; + } + +} + + +defm LS8 : A64I_LDRSTR_unsigned<"LS8", 0b00, 0b0, 0b0, "b", GPR32, byte_simm11>; +defm LS16 : A64I_LDRSTR_unsigned<"LS16", 0b01, 0b0, 0b0, "h", GPR32, hword_simm11>; +defm LS32 : A64I_LDRSTR_unsigned<"LS32", 0b10, 0b0, 0b0, "w", GPR32, word_simm11>; +defm LSFP32 : A64I_LDRSTR_unsigned<"LSFP32", 0b10, 0b1, 0b0, "w", FPR32, word_simm11>; +defm LSFP64 : A64I_LDRSTR_unsigned<"LSFP64", 0b11, 0b1, 0b0, "d", DPR64, dword_simm11>; + + +//===----------------------------------------------------------------------===// +// LS patterns +//===----------------------------------------------------------------------===// + +//===------------------------------ +// 1. Basic infrastructural defs +//===------------------------------ + +// First, some simple classes for !foreach and !subst to use: +class Decls { + dag pattern; +} + +def decls : Decls; +def ALIGN; +def INST; +def OFFSET; +def SHIFT; + +// You can't use !subst on an actual immediate, but you *can* use it on an +// operand record that happens to match a single immediate. So we do. +def imm_eq0 : ImmLeaf; +def imm_eq1 : ImmLeaf; +def imm_eq2 : ImmLeaf; +def imm_eq3 : ImmLeaf; +def imm_eq4 : ImmLeaf; + +// If the low bits of a pointer are known to be 0 then an "or" is just as good +// as addition for computing an offset. This fragment forwards that check for +// TableGen's use. +def add_like_or : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{ return CurDAG->isBaseWithConstantOffset(SDValue(N, 0));}]>; + +// Load/store (unsigned immediate) operations with relocations against global +// symbols (for lo12) are only valid if those symbols have correct alignment +// (since the immediate offset is divided by the access scale, it can't have a +// remainder). +// +// The guaranteed alignment is provided as part of the WrapperSmall +// operation, and checked against one of these. +def any_align : ImmLeaf; +def min_align2 : ImmLeaf= 2; }]>; +def min_align4 : ImmLeaf= 4; }]>; +def min_align8 : ImmLeaf= 8; }]>; +def min_align16 : ImmLeaf= 16; }]>; + +// "Normal" load/store instructions can be used on atomic operations, provided +// the ordering parameter is at most "monotonic". Anything above that needs +// special handling with acquire/release instructions. +class simple_load : PatFrag<(ops node:$ptr), (base node:$ptr), [{ return cast(N)->getOrdering() <= Monotonic;}]>; + +def atomic_load_simple_i8 : simple_load; +def atomic_load_simple_i16 : simple_load; +def atomic_load_simple_i32 : simple_load; + +class simple_store : PatFrag<(ops node:$ptr, node:$val), (base node:$ptr, node:$val), [{ return cast(N)->getOrdering() <= Monotonic;}]>; + +def atomic_store_simple_i8 : simple_store; +def atomic_store_simple_i16 : simple_store; +def atomic_store_simple_i32 : simple_store; + +//===------------------------------ +// 2. SImm11 and SImm9 +//===------------------------------ + +multiclass simm11_pats_byte { +def : Pat<(atomic_load_simple_i8 address), (LS8_LDR Base, Offset )>; +def : Pat<(atomic_store_simple_i8 address, GPR32:$Rt), (LS8_STR GPR32:$Rt, Base, Offset )>; +def : Pat<(zextloadi8 address), (LS8_LDR Base, Offset )>; +def : Pat<(extloadi8 address), (LS8_LDR Base, Offset )>; +def : Pat<(truncstorei8 GPR32:$Rt, address),(LS8_STR GPR32:$Rt, Base, Offset )>; +} + +multiclass simm11_pats_hword { +def : Pat<(atomic_load_simple_i16 address), (LS16_LDR Base, Offset )>; +def : Pat<(atomic_store_simple_i16 address, GPR32:$Rt), (LS16_STR GPR32:$Rt, Base, Offset )>; +def : Pat<(zextloadi16 address), (LS16_LDR Base, Offset )>; +def : Pat<(extloadi16 address), (LS16_LDR Base, Offset )>; +def : Pat<(truncstorei16 GPR32:$Rt, address),(LS16_STR GPR32:$Rt, Base, Offset )>; +} + +multiclass simm11_pats_word { +def : Pat<(atomic_load_simple_i32 address ), (LS32_LDR Base, Offset )>; +def : Pat<(atomic_store_simple_i32 address , GPR32:$Rt), (LS32_STR GPR32:$Rt, Base, Offset )>; +//32 native +def : Pat<(i32 (load address )), (LS32_LDR Base, Offset )>; +def : Pat<(f32 (load address )), (LSFP32_LDR Base, Offset )>; +def : Pat<(store (i32 GPR32:$Rt), address ), (LS32_STR GPR32:$Rt, Base, Offset )>; +def : Pat<(store (f32 FPR32:$Rt), address ), (LSFP32_STR FPR32:$Rt, Base, Offset )>; +} + +def tframeindex_XFORM : SDNodeXForm(N)->getIndex(); return CurDAG->getTargetFrameIndex(FI, MVT::i32);}]>; + +///############################################################################################### +// Straightforward patterns of last resort: a pointer with or without an +// appropriate offset. +defm : simm11_pats_byte<(i32 GPR32:$Rn), (i32 GPR32:$Rn), (i32 0)>; +defm : simm11_pats_hword<(i32 GPR32:$Rn), (i32 GPR32:$Rn), (i32 0)>; +defm : simm11_pats_word<(i32 GPR32:$Rn), (i32 GPR32:$Rn), (i32 0)>; + +defm : simm11_pats_byte<(add GPR32:$Rn, byte_simm11:$SImm11), (i32 GPR32:$Rn), (i32 byte_simm11:$SImm11)>; +defm : simm11_pats_hword<(add GPR32:$Rn, hword_simm11:$SImm11), (i32 GPR32:$Rn), (i32 hword_simm11:$SImm11)>; +defm : simm11_pats_word<(add GPR32:$Rn, word_simm11:$SImm11), (i32 GPR32:$Rn), (i32 word_simm11:$SImm11)>; +// The offset could be hidden behind an "or", of course: +defm : simm11_pats_byte<(add_like_or GPR32:$Rn, byte_simm11:$SImm11), (i32 GPR32:$Rn), (i32 byte_simm11:$SImm11)>; +defm : simm11_pats_hword<(add_like_or GPR32:$Rn, hword_simm11:$SImm11), (i32 GPR32:$Rn), (i32 hword_simm11:$SImm11)>; +defm : simm11_pats_word<(add_like_or GPR32:$Rn, word_simm11:$SImm11), (i32 GPR32:$Rn), (i32 word_simm11:$SImm11)>; +// Global addresses under the small-absolute model should use these +// instructions. There are ELF relocations specifically for it. +defm : simm11_pats_byte<(A64WrapperSmall tglobaladdr:$Hi, tglobaladdr:$Lo12, any_align), (MOVTri_nopat (MOVri_nopat (tglobaladdr:$Lo12)),(tglobaladdr:$Hi)), (i32 0)>; +defm : simm11_pats_hword<(A64WrapperSmall tglobaladdr:$Hi, tglobaladdr:$Lo12, min_align2), (MOVTri_nopat (MOVri_nopat (tglobaladdr:$Lo12)),(tglobaladdr:$Hi)), (i32 0)>; +defm : simm11_pats_word<(A64WrapperSmall tglobaladdr:$Hi, tglobaladdr:$Lo12, min_align4), (MOVTri_nopat (MOVri_nopat (tglobaladdr:$Lo12)),(tglobaladdr:$Hi)), (i32 0)>; + +// External symbols that make it this far should also get standard relocations. +defm : simm11_pats_byte<(A64WrapperSmall texternalsym:$Hi, texternalsym:$Lo12, any_align), (MOVTri_nopat (MOVri_nopat (texternalsym:$Lo12)),(texternalsym:$Hi)), (i32 0)>; +defm : simm11_pats_hword<(A64WrapperSmall texternalsym:$Hi, texternalsym:$Lo12, min_align2), (MOVTri_nopat (MOVri_nopat (texternalsym:$Lo12)),(texternalsym:$Hi)), (i32 0)>; +defm : simm11_pats_word<(A64WrapperSmall texternalsym:$Hi, texternalsym:$Lo12, min_align4), (MOVTri_nopat (MOVri_nopat (texternalsym:$Lo12)),(texternalsym:$Hi)), (i32 0)>; + +defm : simm11_pats_byte<(A64WrapperSmall tconstpool:$Hi, tconstpool:$Lo12, any_align), (MOVTri_nopat (MOVri_nopat (tconstpool:$Lo12)),(tconstpool:$Hi)), (i32 0)>; +defm : simm11_pats_hword<(A64WrapperSmall tconstpool:$Hi, tconstpool:$Lo12, min_align2), (MOVTri_nopat (MOVri_nopat (tconstpool:$Lo12)),(tconstpool:$Hi)), (i32 0)>; +defm : simm11_pats_word<(A64WrapperSmall tconstpool:$Hi, tconstpool:$Lo12, min_align4), (MOVTri_nopat (MOVri_nopat (tconstpool:$Lo12)),(tconstpool:$Hi)), (i32 0)>; + +// We also want to use simm11 instructions for local variables at the moment. +defm : simm11_pats_byte<(i32 frameindex:$Rn), (tframeindex_XFORM tframeindex:$Rn), (i32 0)>; +defm : simm11_pats_hword<(i32 frameindex:$Rn), (tframeindex_XFORM tframeindex:$Rn), (i32 0)>; +defm : simm11_pats_word<(i32 frameindex:$Rn), (tframeindex_XFORM tframeindex:$Rn), (i32 0)>; +///############################################################################################### + + +//===------------------------------ +// 3. Register offset patterns +//===------------------------------ + +multiclass regoff_pats { + +def : Pat<(atomic_load_simple_i8 address ), (LS8_RO_LDR Base, Offset)>; +def : Pat<(atomic_load_simple_i16 address ), (LS16_RO_LDR Base, Offset)>; +def : Pat<(atomic_load_simple_i32 address ), (LS32_RO_LDR Base, Offset)>; + +def : Pat<(atomic_store_simple_i8 address, GPR32:$Rt), (LS8_RO_STR GPR32:$Rt, Base, Offset)>; +def : Pat<(atomic_store_simple_i16 address, GPR32:$Rt), (LS16_RO_STR GPR32:$Rt, Base, Offset)>; +def : Pat<(atomic_store_simple_i32 address, GPR32:$Rt), (LS32_RO_STR GPR32:$Rt, Base, Offset)>; + +def : Pat<(zextloadi8 address ), (LS8_RO_LDR Base, Offset)>; +def : Pat<(zextloadi16 address ), (LS16_RO_LDR Base, Offset)>; + +def : Pat<(extloadi8 address ), (LS8_RO_LDR Base, Offset)>; +def : Pat<(extloadi16 address ), (LS16_RO_LDR Base, Offset)>; + +def : Pat<(truncstorei8 GPR32:$Rt, address ),(LS8_RO_STR GPR32:$Rt, Base, Offset)>; +def : Pat<(truncstorei16 GPR32:$Rt, address ),(LS16_RO_STR GPR32:$Rt, Base, Offset)>; + +//32 native +def : Pat<(i32 (load address) ), (LS32_RO_LDR Base, Offset)>; +def : Pat<(f32 (load address) ), (LSFP32_RO_LDR Base, Offset)>; + +def : Pat<(store (i32 GPR32:$Rt), address ), (LS32_RO_STR GPR32:$Rt, Base, Offset)>; +def : Pat<(store (f32 FPR32:$Rt), address ), (LSFP32_RO_STR FPR32:$Rt, Base, Offset)>; +} + +defm : regoff_pats<(add GPR32:$Rn, GPR32:$Rm), (i32 GPR32:$Rn), (i32 GPR32:$Rm)>; diff --git a/EpiphanyLSOptPass.cpp b/EpiphanyLSOptPass.cpp new file mode 100644 index 0000000..cbeb649 --- /dev/null +++ b/EpiphanyLSOptPass.cpp @@ -0,0 +1,535 @@ +//===-- EpiphanyLoadStoreOptimizer.cpp - Epiphany load / store opt. pass ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a pass that performs load / store related peephole +// optimizations. This pass should be run after register allocation. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "epiphany-ldst-opt" +#include "Epiphany.h" +#include "EpiphanyInstrInfo.h" +#include "EpiphanyRegisterInfo.h" +#include "EpiphanyMachineFunctionInfo.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" +using namespace llvm; + + +STATISTIC(NumLdStMoved, "Number of load / store instructions moved"); +STATISTIC(NumLDRDFormed,"Number of ldrd created before allocation"); +STATISTIC(NumSTRDFormed,"Number of strd created before allocation"); + + +/// isMemoryOp - Returns true if instruction is a memory operation that this +/// pass is capable of operating on. +static bool isMemoryOp(const MachineInstr *MI) { + // When no memory operands are present, conservatively assume unaligned, + // volatile, unfoldable. + if (!MI->hasOneMemOperand()) + return false; + + const MachineMemOperand *MMO = *MI->memoperands_begin(); + + // Don't touch volatile memory accesses - we may be changing their order. + if (MMO->isVolatile()) + return false; + + // Unaligned ldr/str is emulated by some kernels, but unaligned ldm/stm is + // not. + if (MMO->getAlignment() < 4) + return false; + + // str could probably be eliminated entirely, but for now we just want + // to avoid making a mess of it. + // FIXME: Use str as a wildcard to enable better stm folding. + if (MI->getNumOperands() > 0 && MI->getOperand(0).isReg() && + MI->getOperand(0).isUndef()) + return false; + + // Likewise don't mess with references to undefined addresses. + if (MI->getNumOperands() > 1 && MI->getOperand(1).isReg() && + MI->getOperand(1).isUndef()) + return false; + + int Opcode = MI->getOpcode(); + switch (Opcode) { + default: break; + case Epiphany::LS32_LDR: + case Epiphany::LSFP32_LDR: + case Epiphany::LS32_STR: + case Epiphany::LSFP32_STR: + return MI->getOperand(1).isReg(); + } + return false; +} + +static int getMemoryOpOffset(const MachineInstr *MI) { + int Opcode = MI->getOpcode(); + unsigned NumOperands = MI->getDesc().getNumOperands(); + return MI->getOperand(NumOperands-1).getImm() * 4;//only 32bit +} + +/// EpiphanyPreAllocLoadStoreOpt - Pre- register allocation pass that move +/// load / stores from consecutive locations close to make it more +/// likely they will be combined later. + +namespace { + struct EpiphanyPreAllocLoadStoreOpt : public MachineFunctionPass{ + static char ID; + EpiphanyPreAllocLoadStoreOpt() : MachineFunctionPass(ID) {} + + const DataLayout *TD; + const TargetInstrInfo *TII; + const TargetRegisterInfo *TRI; + MachineRegisterInfo *MRI; + MachineFunction *MF; + + virtual bool runOnMachineFunction(MachineFunction &Fn); + + virtual const char *getPassName() const { + return "Epiphany pre- register allocation load / store optimization pass"; + } + + private: + bool CanFormLdStDWord(MachineInstr *Op0, MachineInstr *Op1, DebugLoc &dl, + unsigned &NewOpc, unsigned &EvenReg, + unsigned &OddReg, unsigned &BaseReg, + int &Offset); + bool RescheduleOps(MachineBasicBlock *MBB, + SmallVector &Ops, + unsigned Base, bool isLd, + DenseMap &MI2LocMap); + bool RescheduleLoadStoreInstrs(MachineBasicBlock *MBB); + }; + char EpiphanyPreAllocLoadStoreOpt::ID = 0; +} + +bool EpiphanyPreAllocLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) { + TD = Fn.getTarget().getDataLayout(); + TII = Fn.getTarget().getInstrInfo(); + TRI = Fn.getTarget().getRegisterInfo(); + MRI = &Fn.getRegInfo(); + MF = &Fn; + + bool Modified = false; + for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; + ++MFI) + Modified |= RescheduleLoadStoreInstrs(MFI); + + return Modified; +} + +static bool IsSafeAndProfitableToMove(bool isLd, unsigned Base, + MachineBasicBlock::iterator I, + MachineBasicBlock::iterator E, + SmallPtrSet &MemOps, + SmallSet &MemRegs, + const TargetRegisterInfo *TRI) { + // Are there stores / loads / calls between them? + // FIXME: This is overly conservative. We should make use of alias information + // some day. + SmallSet AddedRegPressure; + while (++I != E) { + if (I->isDebugValue() || MemOps.count(&*I)) + continue; + if (I->isCall() || I->isTerminator() || I->hasUnmodeledSideEffects()) + return false; + if (isLd && I->mayStore()) + return false; + if (!isLd) { + if (I->mayLoad()) + return false; + // It's not safe to move the first 'str' down. + // str r1, [r0] + // strh r5, [r0] + // str r4, [r0, #+4] + if (I->mayStore()) + return false; + } + for (unsigned j = 0, NumOps = I->getNumOperands(); j != NumOps; ++j) { + MachineOperand &MO = I->getOperand(j); + if (!MO.isReg()) + continue; + unsigned Reg = MO.getReg(); + if (MO.isDef() && TRI->regsOverlap(Reg, Base)) + return false; + if (Reg != Base && !MemRegs.count(Reg)) + AddedRegPressure.insert(Reg); + } + } + + // Estimate register pressure increase due to the transformation. + if (MemRegs.size() <= 4) + // Ok if we are moving small number of instructions. + return true; + return AddedRegPressure.size() <= MemRegs.size() * 2; +} + + +/// Copy Op0 and Op1 operands into a new array assigned to MI. +static void concatenateMemOperands(MachineInstr *MI, MachineInstr *Op0, + MachineInstr *Op1) { + assert(MI->memoperands_empty() && "expected a new machineinstr"); + size_t numMemRefs = (Op0->memoperands_end() - Op0->memoperands_begin()) + + (Op1->memoperands_end() - Op1->memoperands_begin()); + + MachineFunction *MF = MI->getParent()->getParent(); + MachineSDNode::mmo_iterator MemBegin = MF->allocateMemRefsArray(numMemRefs); + MachineSDNode::mmo_iterator MemEnd = + std::copy(Op0->memoperands_begin(), Op0->memoperands_end(), MemBegin); + MemEnd = + std::copy(Op1->memoperands_begin(), Op1->memoperands_end(), MemEnd); + MI->setMemRefs(MemBegin, MemEnd); +} + +bool +EpiphanyPreAllocLoadStoreOpt::CanFormLdStDWord(MachineInstr *Op0, MachineInstr *Op1, + DebugLoc &dl, + unsigned &NewOpc, unsigned &EvenReg, + unsigned &OddReg, unsigned &BaseReg, + int &Offset) { + + unsigned Opcode = Op0->getOpcode(); + switch(Op0->getOpcode()){ + case Epiphany::LS32_LDR: + case Epiphany::LSFP32_LDR: NewOpc = Epiphany::LSFP64_LDR;break; + case Epiphany::LSFP32_STR: + case Epiphany::LS32_STR: NewOpc = Epiphany::LSFP64_STR;break; + default: return false; + } + + // Make sure the base address satisfies i64 ld / st alignment requirement. + if (!Op0->hasOneMemOperand() || !(*Op0->memoperands_begin())->getValue() || (*Op0->memoperands_begin())->isVolatile()) + return false; + + unsigned Align = (*Op0->memoperands_begin())->getAlignment(); + const Function *Func = MF->getFunction(); + if (Align < 8) + return false; + + // Then make sure the immediate offset fits. + Offset = getMemoryOpOffset(Op0); + + EvenReg = Op0->getOperand(0).getReg(); + OddReg = Op1->getOperand(0).getReg(); + if (EvenReg == OddReg) + return false; + BaseReg = Op0->getOperand(1).getReg(); + dl = Op0->getDebugLoc(); + return true; +} + +namespace { + struct OffsetCompare { + bool operator()(const MachineInstr *LHS, const MachineInstr *RHS) const { + int LOffset = getMemoryOpOffset(LHS); + int ROffset = getMemoryOpOffset(RHS); + assert(LHS == RHS || LOffset != ROffset); + return LOffset > ROffset; + } + }; +} + +bool EpiphanyPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB, + SmallVector &Ops, + unsigned Base, bool isLd, + DenseMap &MI2LocMap) { + bool RetVal = false; + + // Sort by offset (in reverse order). + std::sort(Ops.begin(), Ops.end(), OffsetCompare()); + + // The loads / stores of the same base are in order. Scan them from first to + // last and check for the following: + // 1. Any def of base. + // 2. Any gaps. + while (Ops.size() > 1) { + unsigned FirstLoc = ~0U; + unsigned LastLoc = 0; + MachineInstr *FirstOp = 0; + MachineInstr *LastOp = 0; + int LastOffset = 0; + //unsigned LastOpcode = 0; + unsigned LastBytes = 0; + unsigned NumMove = 0; + for (int i = Ops.size() - 1; i >= 0; --i) { + MachineInstr *Op = Ops[i]; + unsigned Loc = MI2LocMap[Op]; + if (Loc <= FirstLoc) { + FirstLoc = Loc; + FirstOp = Op; + } + if (Loc >= LastLoc) { + LastLoc = Loc; + LastOp = Op; + } + + //unsigned LSMOpcode = 0;//getLoadStoreMultipleOpcode(Op->getOpcode(), Epiphany_AM::ia); + //if (LastOpcode && LSMOpcode != LastOpcode) + // break; + + int Offset = getMemoryOpOffset(Op); + unsigned Bytes = 4;//getLSMultipleTransferSize(Op); + if (LastBytes) { + if (Bytes != LastBytes || Offset != (LastOffset + (int)Bytes)) + break; + } + LastOffset = Offset; + LastBytes = Bytes; + //LastOpcode = LSMOpcode; + if (++NumMove == 8) // FIXME: Tune this limit. + break; + } + + if (NumMove <= 1) + Ops.pop_back(); + else { + SmallPtrSet MemOps; + SmallSet MemRegs; + for (int i = NumMove-1; i >= 0; --i) { + MemOps.insert(Ops[i]); + MemRegs.insert(Ops[i]->getOperand(0).getReg()); + } + + // Be conservative, if the instructions are too far apart, don't + // move them. We want to limit the increase of register pressure. + bool DoMove = (LastLoc - FirstLoc) <= NumMove*4; // FIXME: Tune this. + if (DoMove) + DoMove = IsSafeAndProfitableToMove(isLd, Base, FirstOp, LastOp, + MemOps, MemRegs, TRI); + if (!DoMove) { + for (unsigned i = 0; i != NumMove; ++i) + Ops.pop_back(); + } else { + // This is the new location for the loads / stores. + MachineBasicBlock::iterator InsertPos = isLd ? FirstOp : LastOp; + while (InsertPos != MBB->end() && (MemOps.count(InsertPos) || InsertPos->isDebugValue())) + ++InsertPos; + + // If we are moving a pair of loads / stores, see if it makes sense + // to try to allocate a pair of registers that can form register pairs. + MachineInstr *Op0 = Ops.back(); + MachineInstr *Op1 = Ops[Ops.size()-2]; + unsigned EvenReg = 0, OddReg = 0; + unsigned BaseReg = 0, DoubleReg = 0; + //bool isT2 = false; + unsigned NewOpc = 0; + int Offset = 0; + DebugLoc dl; + if (NumMove == 2 && CanFormLdStDWord(Op0, Op1, dl, NewOpc, + EvenReg, OddReg, BaseReg, + Offset)) { + Ops.pop_back(); + Ops.pop_back(); + + const MCInstrDesc &MCID = TII->get(NewOpc); + const TargetRegisterClass *TRC = TII->getRegClass(MCID, 0, TRI, *MF); + DoubleReg = MRI->createVirtualRegister(TRC); + + + // Form the pair instruction. + if (isLd) { + MachineInstrBuilder MIB = BuildMI(*MBB, InsertPos, dl, MCID) + .addReg(DoubleReg, RegState::Define) + .addReg(BaseReg); + MIB.addImm(Offset); + concatenateMemOperands(MIB, Op0, Op1); + DEBUG(dbgs() << "Formed " << *MIB << "\n"); + ++NumLDRDFormed; + + //FIXME: i think this is kinda bad, use EXTRACT_SUBREG instead? + + // Collect all the uses of this MI's DPR def for updating later. + SmallVector Uses0,Uses1; + + for (MachineRegisterInfo::use_iterator I = MRI->use_begin(Op0->getOperand(0).getReg()),E = MRI->use_end(); I != E; ++I) + Uses0.push_back(&I.getOperand()); + + for (MachineRegisterInfo::use_iterator I = MRI->use_begin(Op1->getOperand(0).getReg()),E = MRI->use_end(); I != E; ++I) + Uses1.push_back(&I.getOperand()); + + for (SmallVector::const_iterator I = Uses0.begin(), E = Uses0.end(); I != E; ++I) + (*I)->substVirtReg(DoubleReg, Epiphany::sub_even, *TRI); + + for (SmallVector::const_iterator I = Uses1.begin(), E = Uses1.end(); I != E; ++I) + (*I)->substVirtReg(DoubleReg, Epiphany::sub_odd, *TRI); + + } else {//store + + //build our dpr + BuildMI(*MBB, InsertPos, dl, TII->get(Epiphany::REG_SEQUENCE), DoubleReg) + .addReg(Op0->getOperand(0).getReg()) + .addImm(Epiphany::sub_even) + .addReg(Op1->getOperand(0).getReg()) + .addImm(Epiphany::sub_odd); + + + MachineInstrBuilder MIB = BuildMI(*MBB, InsertPos, dl, MCID) + .addReg(DoubleReg, RegState::Kill) + .addReg(BaseReg); + MIB.addImm(Offset); + concatenateMemOperands(MIB, Op0, Op1); + DEBUG(dbgs() << "Formed " << *MIB << "\n"); + ++NumSTRDFormed; + + } + MBB->erase(Op0); + MBB->erase(Op1); + + } else { + for (unsigned i = 0; i != NumMove; ++i) { + MachineInstr *Op = Ops.back(); + Ops.pop_back(); + MBB->splice(InsertPos, MBB, Op); + } + } + + NumLdStMoved += NumMove; + RetVal = true; + } + } + } + + return RetVal; +} + +bool +EpiphanyPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) { + bool RetVal = false; + + DenseMap MI2LocMap; + DenseMap > Base2LdsMap; + DenseMap > Base2StsMap; + SmallVector LdBases; + SmallVector StBases; + + unsigned Loc = 0; + MachineBasicBlock::iterator MBBI = MBB->begin(); + MachineBasicBlock::iterator E = MBB->end(); + while (MBBI != E) { + for (; MBBI != E; ++MBBI) { + MachineInstr *MI = MBBI; + if (MI->isCall() || MI->isTerminator()) { + // Stop at barriers. + ++MBBI; + break; + } + + if (!MI->isDebugValue()) + MI2LocMap[MI] = ++Loc; + + if (!isMemoryOp(MI)) + continue; + + int Opc = MI->getOpcode(); + bool isLd = (Opc == Epiphany::LS32_LDR || Opc == Epiphany::LSFP32_LDR); + unsigned Base = MI->getOperand(1).getReg(); + int Offset = getMemoryOpOffset(MI); + + bool StopHere = false; + if (isLd) { + DenseMap >::iterator BI = + Base2LdsMap.find(Base); + if (BI != Base2LdsMap.end()) { + for (unsigned i = 0, e = BI->second.size(); i != e; ++i) { + if (Offset == getMemoryOpOffset(BI->second[i])) { + StopHere = true; + break; + } + } + if (!StopHere) + BI->second.push_back(MI); + } else { + SmallVector MIs; + MIs.push_back(MI); + Base2LdsMap[Base] = MIs; + LdBases.push_back(Base); + } + } else { + DenseMap >::iterator BI = + Base2StsMap.find(Base); + if (BI != Base2StsMap.end()) { + for (unsigned i = 0, e = BI->second.size(); i != e; ++i) { + if (Offset == getMemoryOpOffset(BI->second[i])) { + StopHere = true; + break; + } + } + if (!StopHere) + BI->second.push_back(MI); + } else { + SmallVector MIs; + MIs.push_back(MI); + Base2StsMap[Base] = MIs; + StBases.push_back(Base); + } + } + + if (StopHere) { + // Found a duplicate (a base+offset combination that's seen earlier). + // Backtrack. + --Loc; + break; + } + } + + // Re-schedule loads. + for (unsigned i = 0, e = LdBases.size(); i != e; ++i) { + unsigned Base = LdBases[i]; + SmallVector &Lds = Base2LdsMap[Base]; + if (Lds.size() > 1) + RetVal |= RescheduleOps(MBB, Lds, Base, true, MI2LocMap); + } + + // Re-schedule stores. + for (unsigned i = 0, e = StBases.size(); i != e; ++i) { + unsigned Base = StBases[i]; + SmallVector &Sts = Base2StsMap[Base]; + if (Sts.size() > 1) + RetVal |= RescheduleOps(MBB, Sts, Base, false, MI2LocMap); + } + + if (MBBI != E) { + Base2LdsMap.clear(); + Base2StsMap.clear(); + LdBases.clear(); + StBases.clear(); + } + } + + return RetVal; +} + + +/// createEpiphanyLoadStoreOptimizationPass - returns an instance of the load / store +/// optimization pass. +FunctionPass *llvm::createEpiphanyLSOptPass() { + return new EpiphanyPreAllocLoadStoreOpt(); +} diff --git a/EpiphanyMCInstLower.cpp b/EpiphanyMCInstLower.cpp new file mode 100644 index 0000000..3ff6c4a --- /dev/null +++ b/EpiphanyMCInstLower.cpp @@ -0,0 +1,120 @@ +//===-- EpiphanyMCInstLower.cpp - Convert Epiphany MachineInstr to an MCInst -==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower Epiphany MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "EpiphanyAsmPrinter.h" +#include "EpiphanyTargetMachine.h" +#include "MCTargetDesc/EpiphanyMCExpr.h" +#include "Utils/EpiphanyBaseInfo.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Target/Mangler.h" + +using namespace llvm; + +MCOperand +EpiphanyAsmPrinter::lowerSymbolOperand(const MachineOperand &MO, + const MCSymbol *Sym) const { + const MCExpr *Expr = 0; + + Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, OutContext); + + switch (MO.getTargetFlags()) { + case EpiphanyII::MO_LO16: + Expr = EpiphanyMCExpr::CreateLo16(Expr, OutContext); + break; + case EpiphanyII::MO_HI16: + Expr = EpiphanyMCExpr::CreateHi16(Expr, OutContext); + break; + case EpiphanyII::MO_NO_FLAG: + // Expr is already correct + break; + default: + llvm_unreachable("Unexpected MachineOperand flag - lowersymboloperand"); + } + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(MO.getOffset(), + OutContext), + OutContext); + + return MCOperand::CreateExpr(Expr); +} + +bool EpiphanyAsmPrinter::lowerOperand(const MachineOperand &MO, + MCOperand &MCOp) const { + switch (MO.getType()) { + default: llvm_unreachable("unknown operand type"); + case MachineOperand::MO_Register: + if (MO.isImplicit()) + return false; + assert(!MO.getSubReg() && "Subregs should be eliminated!"); + MCOp = MCOperand::CreateReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::CreateImm(MO.getImm()); + break; + case MachineOperand::MO_FPImmediate: {// a bit hacky, see arm + APFloat Val = MO.getFPImm()->getValueAPF(); + bool ignored; + Val.convert(APFloat::IEEEdouble, APFloat::rmTowardZero, &ignored); + MCOp = MCOperand::CreateFPImm(Val.convertToDouble()); + break; + } + case MachineOperand::MO_BlockAddress: + MCOp = lowerSymbolOperand(MO, GetBlockAddressSymbol(MO.getBlockAddress())); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO.getSymbolName())); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = lowerSymbolOperand(MO, Mang->getSymbol(MO.getGlobal())); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( + MO.getMBB()->getSymbol(), OutContext)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = lowerSymbolOperand(MO, GetJTISymbol(MO.getIndex())); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = lowerSymbolOperand(MO, GetCPISymbol(MO.getIndex())); + break; + case MachineOperand::MO_RegisterMask: + // Ignore call clobbers + return false; + + } + + return true; +} + +void llvm::LowerEpiphanyMachineInstrToMCInst(const MachineInstr *MI, + MCInst &OutMI, + EpiphanyAsmPrinter &AP) { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + if (AP.lowerOperand(MO, MCOp)) + OutMI.addOperand(MCOp); + } +} diff --git a/EpiphanyMachineFunctionInfo.cpp b/EpiphanyMachineFunctionInfo.cpp new file mode 100644 index 0000000..d2bff76 --- /dev/null +++ b/EpiphanyMachineFunctionInfo.cpp @@ -0,0 +1,18 @@ +//===-- EpiphanyMachineFuctionInfo.cpp - Epiphany machine function info -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file just contains the anchor for the EpiphanyMachineFunctionInfo to +// force vtable emission. +// +//===----------------------------------------------------------------------===// +#include "EpiphanyMachineFunctionInfo.h" + +using namespace llvm; + +void EpiphanyMachineFunctionInfo::anchor() { } diff --git a/EpiphanyMachineFunctionInfo.h b/EpiphanyMachineFunctionInfo.h new file mode 100644 index 0000000..1ef316e --- /dev/null +++ b/EpiphanyMachineFunctionInfo.h @@ -0,0 +1,149 @@ +//=- EpiphanyMachineFuctionInfo.h - Epiphany machine function info -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares Epiphany-specific per-machine-function information. +// +//===----------------------------------------------------------------------===// + +#ifndef EPIPHANYMACHINEFUNCTIONINFO_H +#define EPIPHANYMACHINEFUNCTIONINFO_H + +#include "llvm/CodeGen/MachineFunction.h" + +namespace llvm { + +/// This class is derived from MachineFunctionInfo and contains private Epiphany +/// target-specific information for each MachineFunction. +class EpiphanyMachineFunctionInfo : public MachineFunctionInfo { + virtual void anchor(); + + /// Number of bytes of arguments this function has on the stack. If the callee + /// is expected to restore the argument stack this should be a multiple of 16, + /// all usable during a tail call. + /// + /// The alternative would forbid tail call optimisation in some cases: if we + /// want to transfer control from a function with 8-bytes of stack-argument + /// space to a function with 16-bytes then misalignment of this value would + /// make a stack adjustment necessary, which could not be undone by the + /// callee. + unsigned BytesInStackArgArea; + + /// The number of bytes to restore to deallocate space for incoming + /// arguments. Canonically 0 in the C calling convention, but non-zero when + /// callee is expected to pop the args. + unsigned ArgumentStackToRestore; + + /// If the stack needs to be adjusted on frame entry in two stages, this + /// records the size of the first adjustment just prior to storing + /// callee-saved registers. The callee-saved slots are addressed assuming + /// SP == - InitialStackAdjust. + unsigned InitialStackAdjust; + + /// Number of local-dynamic TLS accesses. + unsigned NumLocalDynamics; + + /// @see Epiphany Procedure Call Standard, B.3 + /// + /// The Frame index of the area where LowerFormalArguments puts the + /// general-purpose registers that might contain variadic parameters. + int VariadicGPRIdx; + + /// @see Epiphany Procedure Call Standard, B.3 + /// + /// The size of the frame object used to store the general-purpose registers + /// which might contain variadic arguments. This is the offset from + /// VariadicGPRIdx to what's stored in __gr_top. + unsigned VariadicGPRSize; + + /// @see Epiphany Procedure Call Standard, B.3 + /// + /// The Frame index of the area where LowerFormalArguments puts the + /// floating-point registers that might contain variadic parameters. + int VariadicFPRIdx; + + /// @see Epiphany Procedure Call Standard, B.3 + /// + /// The size of the frame object used to store the floating-point registers + /// which might contain variadic arguments. This is the offset from + /// VariadicFPRIdx to what's stored in __vr_top. + unsigned VariadicFPRSize; + + /// @see Epiphany Procedure Call Standard, B.3 + /// + /// The Frame index of an object pointing just past the last known stacked + /// argument on entry to a variadic function. This goes into the __stack field + /// of the va_list type. + int VariadicStackIdx; + + /// The offset of the frame pointer from the stack pointer on function + /// entry. This is expected to be negative. + int FramePointerOffset; + +public: + EpiphanyMachineFunctionInfo() + : BytesInStackArgArea(0), + ArgumentStackToRestore(0), + InitialStackAdjust(0), + NumLocalDynamics(0), + VariadicGPRIdx(0), + VariadicGPRSize(0), + VariadicFPRIdx(0), + VariadicFPRSize(0), + VariadicStackIdx(0), + FramePointerOffset(0) {} + + explicit EpiphanyMachineFunctionInfo(MachineFunction &MF) + : BytesInStackArgArea(0), + ArgumentStackToRestore(0), + InitialStackAdjust(0), + NumLocalDynamics(0), + VariadicGPRIdx(0), + VariadicGPRSize(0), + VariadicFPRIdx(0), + VariadicFPRSize(0), + VariadicStackIdx(0), + FramePointerOffset(0) {} + + unsigned getBytesInStackArgArea() const { return BytesInStackArgArea; } + void setBytesInStackArgArea (unsigned bytes) { BytesInStackArgArea = bytes;} + + unsigned getArgumentStackToRestore() const { return ArgumentStackToRestore; } + void setArgumentStackToRestore(unsigned bytes) { + ArgumentStackToRestore = bytes; + } + + unsigned getInitialStackAdjust() const { return InitialStackAdjust; } + void setInitialStackAdjust(unsigned bytes) { InitialStackAdjust = bytes; } + + unsigned getNumLocalDynamicTLSAccesses() const { return NumLocalDynamics; } + void incNumLocalDynamicTLSAccesses() { ++NumLocalDynamics; } + + int getVariadicGPRIdx() const { return VariadicGPRIdx; } + void setVariadicGPRIdx(int Idx) { VariadicGPRIdx = Idx; } + + unsigned getVariadicGPRSize() const { return VariadicGPRSize; } + void setVariadicGPRSize(unsigned Size) { VariadicGPRSize = Size; } + + int getVariadicFPRIdx() const { return VariadicFPRIdx; } + void setVariadicFPRIdx(int Idx) { VariadicFPRIdx = Idx; } + + unsigned getVariadicFPRSize() const { return VariadicFPRSize; } + void setVariadicFPRSize(unsigned Size) { VariadicFPRSize = Size; } + + int getVariadicStackIdx() const { return VariadicStackIdx; } + void setVariadicStackIdx(int Idx) { VariadicStackIdx = Idx; } + + int getFramePointerOffset() const { return FramePointerOffset; } + void setFramePointerOffset(int Idx) { FramePointerOffset = Idx; } + +}; + +} // End llvm namespace + +#endif diff --git a/EpiphanyRegisterInfo.cpp b/EpiphanyRegisterInfo.cpp new file mode 100644 index 0000000..45fec03 --- /dev/null +++ b/EpiphanyRegisterInfo.cpp @@ -0,0 +1,166 @@ +//===- EpiphanyRegisterInfo.cpp - Epiphany Register Information -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Epiphany implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + + +#include "EpiphanyRegisterInfo.h" +#include "EpiphanyFrameLowering.h" +#include "EpiphanyMachineFunctionInfo.h" +#include "EpiphanyTargetMachine.h" +#include "MCTargetDesc/EpiphanyMCTargetDesc.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/CodeGen/VirtRegMap.h" +#include "llvm/ADT/BitVector.h" + +#define GET_REGINFO_TARGET_DESC +#include "EpiphanyGenRegisterInfo.inc" + +using namespace llvm; + +EpiphanyRegisterInfo::EpiphanyRegisterInfo(const EpiphanyInstrInfo &tii, + const EpiphanySubtarget &sti) + : EpiphanyGenRegisterInfo(Epiphany::LR), TII(tii) { +} + +const uint16_t * +EpiphanyRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + return CSR_PCS_SaveList; +} + +const uint32_t* +EpiphanyRegisterInfo::getCallPreservedMask(CallingConv::ID) const { + return CSR_PCS_RegMask; +} + +const TargetRegisterClass * +EpiphanyRegisterInfo::getCrossCopyRegClass(const TargetRegisterClass *RC) const { + //if (RC == &Epiphany::FlagClassRegClass) + // return &Epiphany::GPR32RegClass; + + return RC; +} + + + +BitVector +EpiphanyRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + + Reserved.set(Epiphany::SP); + Reserved.set(Epiphany::R63);// hack: dst for cmp + //constants + Reserved.set(Epiphany::R28); + Reserved.set(Epiphany::R29); + Reserved.set(Epiphany::R30); + Reserved.set(Epiphany::R31); + + Reserved.set(Epiphany::NZCV); + + if (TFI->hasFP(MF)) { + Reserved.set(Epiphany::R11); + } + + return Reserved; +} + +void +EpiphanyRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MBBI, + int SPAdj, + unsigned FIOperandNum, + RegScavenger *RS) const { + assert(SPAdj == 0 && "Cannot deal with nonzero SPAdj yet"); + MachineInstr &MI = *MBBI; + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const EpiphanyFrameLowering *TFI = static_cast(MF.getTarget().getFrameLowering()); + + // In order to work out the base and offset for addressing, the FrameLowering + // code needs to know (sometimes) whether the instruction is storing/loading a + // callee-saved register, or whether it's a more generic + // operation. Fortunately the frame indices are used *only* for that purpose + // and are contiguous, so we can check here. + const std::vector &CSI = MFI->getCalleeSavedInfo(); + int MinCSFI = 0; + int MaxCSFI = -1; + + if (CSI.size()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); + } + + int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); + bool IsCalleeSaveOp = FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI; + + unsigned FrameReg; + int64_t Offset; + Offset = TFI->resolveFrameIndexReference(MF, FrameIndex, FrameReg, SPAdj, IsCalleeSaveOp); + + Offset += MI.getOperand(FIOperandNum + 1).getImm(); + + // DBG_VALUE instructions have no real restrictions so they can be handled + // easily. + if (MI.isDebugValue()) { + MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/ false); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); + return; + } + + int MinOffset, MaxOffset, OffsetScale; + if (MI.getOpcode() == Epiphany::ADDri) { + MinOffset = -(0x3FF); + MaxOffset = 0x3FF; + OffsetScale = 1; + } else { + // Load/store of a stack object + TII.getAddressConstraints(MI, OffsetScale, MinOffset, MaxOffset); + } + + // The frame lowering has told us a base and offset it thinks we should use to + // access this variable, but it's still up to us to make sure the values are + // legal for the instruction in question. + if (Offset % OffsetScale != 0 || Offset < MinOffset || Offset > MaxOffset) { + unsigned BaseReg = MF.getRegInfo().createVirtualRegister(&Epiphany::GPR32RegClass); + EPIPHemitRegUpdate(MBB, MBBI, MBBI->getDebugLoc(), TII, BaseReg, FrameReg, BaseReg, Offset); + FrameReg = BaseReg; + Offset = 0; + } + + // Negative offsets are expected if we address from FP, but for + // now this checks nothing has gone horribly wrong. + assert(Offset >= 0 && "Unexpected negative offset from SP"); + + MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false, false, true); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset / OffsetScale); +} + +unsigned +EpiphanyRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + + if (TFI->hasFP(MF)) + return Epiphany::R11; + else + return Epiphany::SP; +} + +bool +EpiphanyRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + const EpiphanyFrameLowering *AFI = static_cast(TFI); + return AFI->useFPForAddressing(MF); +} diff --git a/EpiphanyRegisterInfo.h b/EpiphanyRegisterInfo.h new file mode 100644 index 0000000..c626653 --- /dev/null +++ b/EpiphanyRegisterInfo.h @@ -0,0 +1,84 @@ +//==- EpiphanyRegisterInfo.h - Epiphany Register Information Impl -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Epiphany implementation of the MCRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_EPIPHANYREGISTERINFO_H +#define LLVM_TARGET_EPIPHANYREGISTERINFO_H + +#include "llvm/Target/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "EpiphanyGenRegisterInfo.inc" + +namespace llvm { + +class EpiphanyInstrInfo; +class EpiphanySubtarget; + +/// Register allocation hints. +namespace EPIPHANYRI { + enum { + RegPairOdd = 1, + RegPairEven = 2 + }; +} + +struct EpiphanyRegisterInfo : public EpiphanyGenRegisterInfo { +private: + const EpiphanyInstrInfo &TII; + +public: + EpiphanyRegisterInfo(const EpiphanyInstrInfo &tii, + const EpiphanySubtarget &sti); + + const uint16_t *getCalleeSavedRegs(const MachineFunction *MF = 0) const; + const uint32_t *getCallPreservedMask(CallingConv::ID) const; + + const uint32_t *getTLSDescCallPreservedMask() const; + + BitVector getReservedRegs(const MachineFunction &MF) const; + unsigned getFrameRegister(const MachineFunction &MF) const; + + void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + unsigned FIOperandNum, + RegScavenger *Rs = NULL) const; + + /// getCrossCopyRegClass - Returns a legal register class to copy a register + /// in the specified class to or from. Returns original class if it is + /// possible to copy between a two registers of the specified class. + const TargetRegisterClass * + getCrossCopyRegClass(const TargetRegisterClass *RC) const; + + /// getLargestLegalSuperClass - Returns the largest super class of RC that is + /// legal to use in the current sub-target and has the same spill size. + const TargetRegisterClass* + getLargestLegalSuperClass(const TargetRegisterClass *RC) const { + //if (RC == &Epiphany::tcGPR32RegClass) + // return &Epiphany::GPR32RegClass; + + return RC; + } + + bool requiresRegisterScavenging(const MachineFunction &MF) const { + return true; + } + + bool requiresFrameIndexScavenging(const MachineFunction &MF) const { + return true; + } + + bool useFPForScavengingIndex(const MachineFunction &MF) const; +}; + +} // end namespace llvm + +#endif // LLVM_TARGET_EPIPHANYREGISTERINFO_H diff --git a/EpiphanyRegisterInfo.td b/EpiphanyRegisterInfo.td new file mode 100644 index 0000000..75e2916 --- /dev/null +++ b/EpiphanyRegisterInfo.td @@ -0,0 +1,102 @@ +//===- EpiphanyRegisterInfo.td - ARM Register defs ----------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains declarations that describe the Epiphany register file +// +//===----------------------------------------------------------------------===// + +let Namespace = "Epiphany" in { +def sub_even : SubRegIndex; +def sub_odd : SubRegIndex; +} + +// Registers are identified with 5-bit ID numbers. +class EpiphanyReg enc, string n> : Register { + let HWEncoding = enc; + let Namespace = "Epiphany"; +} + +class EpiphanyRegWithSubs enc, string n, list subregs = []> : EpiphanyReg { + let SubRegs = subregs; + let CoveredBySubRegs = 1; +} + +//===----------------------------------------------------------------------===// +// Integer registers: w0-w30, wzr, wsp, x0-x30, xzr, sp +//===----------------------------------------------------------------------===// + +foreach Index = 0-12 in { + def R#Index : EpiphanyReg< Index, "r"#Index>, DwarfRegNum<[Index]>; +} + +def SP : EpiphanyReg<13, "sp">, DwarfRegNum<[13]>; +def LR : EpiphanyReg<14, "lr">, DwarfRegNum<[14]>; + +foreach Index = 15-63 in { + def R#Index : EpiphanyReg< Index, "r"#Index>, DwarfRegNum<[Index]>; +} + +let SubRegIndices = [sub_even, sub_odd] in { +def D0 : EpiphanyRegWithSubs<0, "d0", [R0, R1]>, DwarfRegNum<[0,1]>; +def D1 : EpiphanyRegWithSubs<2, "d1", [R2, R3]>, DwarfRegNum<[2,3]>; +def D2 : EpiphanyRegWithSubs<4, "d2", [R4, R5]>, DwarfRegNum<[4,5]>; +def D3 : EpiphanyRegWithSubs<6, "d3", [R6, R7]>, DwarfRegNum<[6,7]>; +def D4 : EpiphanyRegWithSubs<8, "d4", [R8, R9]>, DwarfRegNum<[8,9]>; +def D5 : EpiphanyRegWithSubs<10, "d5", [R10, R11]>, DwarfRegNum<[10,11]>; + +def D6 : EpiphanyRegWithSubs<12, "d6", [R12, SP]>, DwarfRegNum<[12,13]>; +def D7 : EpiphanyRegWithSubs<14, "d7", [LR, R15]>, DwarfRegNum<[14,15]>; + +def D8 : EpiphanyRegWithSubs<16, "d8", [R16, R17]>, DwarfRegNum<[16,17]>; +def D9 : EpiphanyRegWithSubs<18, "d9", [R18, R19]>, DwarfRegNum<[18,19]>; +def D10 : EpiphanyRegWithSubs<20, "d10", [R20, R21]>, DwarfRegNum<[20,21]>; +def D11 : EpiphanyRegWithSubs<22, "d11", [R22, R23]>, DwarfRegNum<[22,23]>; +def D12 : EpiphanyRegWithSubs<24, "d12", [R24, R25]>, DwarfRegNum<[24,25]>; +def D13 : EpiphanyRegWithSubs<26, "d13", [R26, R27]>, DwarfRegNum<[26,27]>; +def D14 : EpiphanyRegWithSubs<28, "d14", [R28, R29]>, DwarfRegNum<[28,29]>; +def D15 : EpiphanyRegWithSubs<30, "d15", [R30, R31]>, DwarfRegNum<[30,31]>; +def D16 : EpiphanyRegWithSubs<32, "d16", [R32, R33]>, DwarfRegNum<[32,33]>; +def D17 : EpiphanyRegWithSubs<34, "d17", [R34, R35]>, DwarfRegNum<[34,35]>; +def D18 : EpiphanyRegWithSubs<36, "d18", [R36, R37]>, DwarfRegNum<[36,37]>; +def D19 : EpiphanyRegWithSubs<38, "d19", [R38, R39]>, DwarfRegNum<[38,39]>; +def D20 : EpiphanyRegWithSubs<40, "d20", [R40, R41]>, DwarfRegNum<[40,41]>; +def D21 : EpiphanyRegWithSubs<42, "d21", [R42, R43]>, DwarfRegNum<[42,43]>; +def D22 : EpiphanyRegWithSubs<44, "d22", [R44, R45]>, DwarfRegNum<[44,45]>; +def D23 : EpiphanyRegWithSubs<46, "d23", [R46, R47]>, DwarfRegNum<[46,47]>; +def D24 : EpiphanyRegWithSubs<48, "d24", [R48, R49]>, DwarfRegNum<[48,49]>; +def D25 : EpiphanyRegWithSubs<50, "d25", [R50, R51]>, DwarfRegNum<[50,51]>; +def D26 : EpiphanyRegWithSubs<52, "d26", [R52, R53]>, DwarfRegNum<[52,53]>; +def D27 : EpiphanyRegWithSubs<54, "d27", [R54, R55]>, DwarfRegNum<[54,55]>; +def D28 : EpiphanyRegWithSubs<56, "d28", [R56, R57]>, DwarfRegNum<[56,57]>; +def D29 : EpiphanyRegWithSubs<58, "d29", [R58, R59]>, DwarfRegNum<[58,59]>; +def D30 : EpiphanyRegWithSubs<60, "d30", [R60, R61]>, DwarfRegNum<[60,61]>; +// def D31 : EpiphanyRegWithSubs<62, "d31", [R62, R63]>, DwarfRegNum<[62,63]>; +} + +// Note that the order of registers is important for the Disassembler here: +// tablegen uses it to form MCRegisterClass::getRegister, which we assume can +// take an encoding value. +def GPR32 : RegisterClass<"Epiphany", [i32], 32, (add (sequence "R%u", 0, 12), LR, SP, (sequence "R%u", 15, 63))> { +} + +def FPR32 : RegisterClass<"Epiphany", [f32], 32, (add GPR32)> { +} + +def DPR64 : RegisterClass<"Epiphany", [i64,f64], 64, (sequence "D%u", 0, 30)> { +} + +// Flags register +def NZCV : Register<"nzcv"> { + let Namespace = "Epiphany"; +} + +def FlagClass : RegisterClass<"Epiphany", [i32], 32, (add NZCV)> { + let CopyCost = -1; + let isAllocatable = 0; +} diff --git a/EpiphanySchedule.td b/EpiphanySchedule.td new file mode 100644 index 0000000..0988acb --- /dev/null +++ b/EpiphanySchedule.td @@ -0,0 +1,10 @@ +//===- EpiphanySchedule.td - Epiphany Scheduling Definitions -*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +def GenericItineraries : ProcessorItineraries<[], [], []>; diff --git a/EpiphanySelectionDAGInfo.cpp b/EpiphanySelectionDAGInfo.cpp new file mode 100644 index 0000000..52493ac --- /dev/null +++ b/EpiphanySelectionDAGInfo.cpp @@ -0,0 +1,25 @@ +//===-- EpiphanySelectionDAGInfo.cpp - Epiphany SelectionDAG Info -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the EpiphanySelectionDAGInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "arm-selectiondag-info" +#include "EpiphanyTargetMachine.h" +#include "llvm/CodeGen/SelectionDAG.h" +using namespace llvm; + +EpiphanySelectionDAGInfo::EpiphanySelectionDAGInfo(const EpiphanyTargetMachine &TM) + : TargetSelectionDAGInfo(TM), + Subtarget(&TM.getSubtarget()) { +} + +EpiphanySelectionDAGInfo::~EpiphanySelectionDAGInfo() { +} diff --git a/EpiphanySelectionDAGInfo.h b/EpiphanySelectionDAGInfo.h new file mode 100644 index 0000000..4f4a6a6 --- /dev/null +++ b/EpiphanySelectionDAGInfo.h @@ -0,0 +1,32 @@ +//===-- EpiphanySelectionDAGInfo.h - Epiphany SelectionDAG Info ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Epiphany subclass for TargetSelectionDAGInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EPIPHANYSELECTIONDAGINFO_H +#define LLVM_EPIPHANYSELECTIONDAGINFO_H + +#include "llvm/Target/TargetSelectionDAGInfo.h" + +namespace llvm { + +class EpiphanyTargetMachine; + +class EpiphanySelectionDAGInfo : public TargetSelectionDAGInfo { + const EpiphanySubtarget *Subtarget; +public: + explicit EpiphanySelectionDAGInfo(const EpiphanyTargetMachine &TM); + ~EpiphanySelectionDAGInfo(); +}; + +} + +#endif diff --git a/EpiphanySubtarget.cpp b/EpiphanySubtarget.cpp new file mode 100644 index 0000000..9315fb0 --- /dev/null +++ b/EpiphanySubtarget.cpp @@ -0,0 +1,41 @@ +//===-- EpiphanySubtarget.cpp - Epiphany Subtarget Information --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Epiphany specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#include "EpiphanySubtarget.h" +#include "EpiphanyRegisterInfo.h" +#include "MCTargetDesc/EpiphanyMCTargetDesc.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/Target/TargetSubtargetInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/ADT/SmallVector.h" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "EpiphanyGenSubtargetInfo.inc" + +using namespace llvm; + +EpiphanySubtarget::EpiphanySubtarget(StringRef TT, StringRef CPU, StringRef FS) + : EpiphanyGenSubtargetInfo(TT, CPU, FS) + , TargetTriple(TT) { + + ParseSubtargetFeatures(CPU, FS); +} + +bool EpiphanySubtarget::GVIsIndirectSymbol(const GlobalValue *GV, + Reloc::Model RelocM) const { + if (RelocM == Reloc::Static) + return false; + + return !GV->hasLocalLinkage() && !GV->hasHiddenVisibility(); +} diff --git a/EpiphanySubtarget.h b/EpiphanySubtarget.h new file mode 100644 index 0000000..85d9139 --- /dev/null +++ b/EpiphanySubtarget.h @@ -0,0 +1,51 @@ +//==-- EpiphanySubtarget.h - Define Subtarget for the Epiphany ---*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Epiphany specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_EPIPHANY_SUBTARGET_H +#define LLVM_TARGET_EPIPHANY_SUBTARGET_H + +#include "llvm/ADT/Triple.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +#define GET_SUBTARGETINFO_HEADER +#include "EpiphanyGenSubtargetInfo.inc" + +#include + +namespace llvm { +class StringRef; +class GlobalValue; + +class EpiphanySubtarget : public EpiphanyGenSubtargetInfo { +protected: + /// TargetTriple - What processor and OS we're targeting. + Triple TargetTriple; +public: + /// This constructor initializes the data members to match that + /// of the specified triple. + /// + EpiphanySubtarget(StringRef TT, StringRef CPU, StringRef FS); + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + + bool GVIsIndirectSymbol(const GlobalValue *GV, Reloc::Model RelocM) const; + + bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); } + bool isTargetLinux() const { return TargetTriple.getOS() == Triple::Linux; } + +}; +} // End llvm namespace + +#endif // LLVM_TARGET_EPIPHANY_SUBTARGET_H diff --git a/EpiphanyTargetMachine.cpp b/EpiphanyTargetMachine.cpp new file mode 100644 index 0000000..bbe7e80 --- /dev/null +++ b/EpiphanyTargetMachine.cpp @@ -0,0 +1,95 @@ +//===-- EpiphanyTargetMachine.cpp - Define TargetMachine for Epiphany -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation of the EpiphanyTargetMachine +// methods. Principally just setting up the passes needed to generate correct +// code on this architecture. +// +//===----------------------------------------------------------------------===// + +#include "Epiphany.h" +#include "EpiphanyTargetMachine.h" +#include "MCTargetDesc/EpiphanyMCTargetDesc.h" +#include "llvm/PassManager.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; + +static cl::opt +EnableLSD("double-ls", cl::Hidden, + cl::desc("Enable double loads and stores"), + cl::init(false)); + + +extern "C" void LLVMInitializeEpiphanyTarget() { + RegisterTargetMachine X(TheEpiphanyTarget); +} + +EpiphanyTargetMachine::EpiphanyTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) + : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL), + Subtarget(TT, CPU, FS), + InstrInfo(Subtarget), + DL("e-p:32:32-i8:8:8-i16:16:16-i32:32:32-f32:32:32-i64:64:64-f64:64:64-s64:64:64-S64:64:64-a0:32:32"), + TLInfo(*this), + TSInfo(*this), + FrameLowering(Subtarget) { +} + +namespace { +/// Epiphany Code Generator Pass Configuration Options. +class EpiphanyPassConfig : public TargetPassConfig { +public: + EpiphanyPassConfig(EpiphanyTargetMachine *TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) {} + + EpiphanyTargetMachine &getEpiphanyTargetMachine() const { + return getTM(); + } + + const EpiphanySubtarget &getEpiphanySubtarget() const { + return *getEpiphanyTargetMachine().getSubtargetImpl(); + } + + virtual bool addInstSelector(); + virtual bool addPreEmitPass(); + virtual bool addPreRegAlloc(); + virtual bool addPostRegAlloc(); +}; +} // namespace + +TargetPassConfig *EpiphanyTargetMachine::createPassConfig(PassManagerBase &PM) { + return new EpiphanyPassConfig(this, PM); +} + +bool EpiphanyPassConfig::addPreEmitPass() { + addPass(&UnpackMachineBundlesID); + return true; +} + +bool EpiphanyPassConfig::addInstSelector() { + addPass(createEpiphanyISelDAG(getEpiphanyTargetMachine(), getOptLevel())); + return false; +} + +bool EpiphanyPassConfig::addPreRegAlloc() { + if (EnableLSD) + addPass(createEpiphanyLSOptPass()); + return true; +} + +bool EpiphanyPassConfig::addPostRegAlloc() { + addPass(createEpiphanyCondMovPass(getEpiphanyTargetMachine())); + return true; +} \ No newline at end of file diff --git a/EpiphanyTargetMachine.h b/EpiphanyTargetMachine.h new file mode 100644 index 0000000..c9e2741 --- /dev/null +++ b/EpiphanyTargetMachine.h @@ -0,0 +1,69 @@ +//=== EpiphanyTargetMachine.h - Define TargetMachine for Epiphany -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Epiphany specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EPIPHANYTARGETMACHINE_H +#define LLVM_EPIPHANYTARGETMACHINE_H + +#include "EpiphanyFrameLowering.h" +#include "EpiphanyISelLowering.h" +#include "EpiphanyInstrInfo.h" +#include "EpiphanySelectionDAGInfo.h" +#include "EpiphanySubtarget.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +class EpiphanyTargetMachine : public LLVMTargetMachine { + EpiphanySubtarget Subtarget; + EpiphanyInstrInfo InstrInfo; + const DataLayout DL; + EpiphanyTargetLowering TLInfo; + EpiphanySelectionDAGInfo TSInfo; + EpiphanyFrameLowering FrameLowering; + +public: + EpiphanyTargetMachine(const Target &T, StringRef TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); + + const EpiphanyInstrInfo *getInstrInfo() const { + return &InstrInfo; + } + + const EpiphanyFrameLowering *getFrameLowering() const { + return &FrameLowering; + } + + const EpiphanyTargetLowering *getTargetLowering() const { + return &TLInfo; + } + + const EpiphanySelectionDAGInfo *getSelectionDAGInfo() const { + return &TSInfo; + } + + const EpiphanySubtarget *getSubtargetImpl() const { return &Subtarget; } + + const DataLayout *getDataLayout() const { return &DL; } + + const TargetRegisterInfo *getRegisterInfo() const { + return &InstrInfo.getRegisterInfo(); + } + TargetPassConfig *createPassConfig(PassManagerBase &PM); +}; + +} + +#endif diff --git a/EpiphanyTargetObjectFile.cpp b/EpiphanyTargetObjectFile.cpp new file mode 100644 index 0000000..1edba97 --- /dev/null +++ b/EpiphanyTargetObjectFile.cpp @@ -0,0 +1,24 @@ +//===-- EpiphanyTargetObjectFile.cpp - Epiphany Object Info -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file deals with any Epiphany specific requirements on object files. +// +//===----------------------------------------------------------------------===// + + +#include "EpiphanyTargetObjectFile.h" + +using namespace llvm; + +void +EpiphanyLinuxTargetObjectFile::Initialize(MCContext &Ctx, + const TargetMachine &TM) { + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + InitializeELF(TM.Options.UseInitArray); +} diff --git a/EpiphanyTargetObjectFile.h b/EpiphanyTargetObjectFile.h new file mode 100644 index 0000000..c632a41 --- /dev/null +++ b/EpiphanyTargetObjectFile.h @@ -0,0 +1,31 @@ +//===-- EpiphanyTargetObjectFile.h - Epiphany Object Info ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file deals with any Epiphany specific requirements on object files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_EPIPHANY_TARGETOBJECTFILE_H +#define LLVM_TARGET_EPIPHANY_TARGETOBJECTFILE_H + +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetLoweringObjectFile.h" + +namespace llvm { + + /// EpiphanyLinuxTargetObjectFile - This implementation is used for linux + /// Epiphany. + class EpiphanyLinuxTargetObjectFile : public TargetLoweringObjectFileELF { + virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); + }; + +} // end namespace llvm + +#endif diff --git a/InstPrinter/CMakeLists.txt b/InstPrinter/CMakeLists.txt new file mode 100644 index 0000000..0194547 --- /dev/null +++ b/InstPrinter/CMakeLists.txt @@ -0,0 +1,8 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMEpiphanyAsmPrinter + EpiphanyInstPrinter.cpp + ) + +add_dependencies(LLVMEpiphanyAsmPrinter EpiphanyCommonTableGen) + diff --git a/InstPrinter/EpiphanyInstPrinter.cpp b/InstPrinter/EpiphanyInstPrinter.cpp new file mode 100644 index 0000000..d8a6f75 --- /dev/null +++ b/InstPrinter/EpiphanyInstPrinter.cpp @@ -0,0 +1,118 @@ +//==-- EpiphanyInstPrinter.cpp - Convert Epiphany MCInst to assembly syntax --==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an Epiphany MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "EpiphanyInstPrinter.h" +#include "MCTargetDesc/EpiphanyMCTargetDesc.h" +#include "Utils/EpiphanyBaseInfo.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define GET_INSTRUCTION_NAME +#define PRINT_ALIAS_INSTR +#include "EpiphanyGenAsmWriter.inc" + +EpiphanyInstPrinter::EpiphanyInstPrinter(const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI) : + MCInstPrinter(MAI, MII, MRI) { + // Initialize the set of available features. + setAvailableFeatures(STI.getFeatureBits()); +} + +void EpiphanyInstPrinter::printAddSubImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O) { + const MCOperand &Imm11Op = MI->getOperand(OpNum); + int64_t Imm11 = Imm11Op.getImm(); + assert((Imm11 <= 1023 && Imm11 >= -1024) && "Invalid immediate for add/sub imm"); + + O << "#" << Imm11; +} + +void EpiphanyInstPrinter::printBareImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNum); + O << MO.getImm(); +} + + +void EpiphanyInstPrinter::printCondCodeOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNum); + + O << A64CondCodeToString(static_cast(MO.getImm())); +} + +template void +EpiphanyInstPrinter::printLabelOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNum); + + if (!MO.isImm()) { + printOperand(MI, OpNum, O); + return; + } + +//we do currently not support branches to immediates that are not labels +assert(MO.isImm() && "unknown operand kind in printLabelOperand (imm?)"); +} + +void EpiphanyInstPrinter::printOffsetUImm11Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O, int MemSize) { + const MCOperand &MOImm = MI->getOperand(OpNum); + int32_t Imm = MOImm.getImm();// * MemSize; + + O << "#" << Imm; +} + +void EpiphanyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + unsigned Reg = Op.getReg(); + O << getRegisterName(Reg); + } else if (Op.isImm()) { + O << '#' << Op.getImm(); + } else { + assert(Op.isExpr() && "unknown operand kind in printOperand"); + // If a symbolic branch target was added as a constant expression then print + // that address in hex. + const MCConstantExpr *BranchTarget = dyn_cast(Op.getExpr()); + int64_t Address; + if (BranchTarget && BranchTarget->EvaluateAsAbsolute(Address)) { + O << "0x"; + O.write_hex(Address); + } + else { + // Otherwise, just print the expression. + O << *Op.getExpr(); + } + } +} + +void EpiphanyInstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNum, + raw_ostream &o) { + const MCOperand &MOImm = MI->getOperand(OpNum); + assert(MOImm.isFPImm() && "not float operand in printFPImmOperand"); + o << '#' << format("%.8f", MOImm.getFPImm()); +} + +void EpiphanyInstPrinter::printInst(const MCInst *MI, raw_ostream &O, + StringRef Annot) { +if (!printAliasInstr(MI, O)) + printInstruction(MI, O); + + printAnnotation(O, Annot); +} diff --git a/InstPrinter/EpiphanyInstPrinter.h b/InstPrinter/EpiphanyInstPrinter.h new file mode 100644 index 0000000..c69b4e5 --- /dev/null +++ b/InstPrinter/EpiphanyInstPrinter.h @@ -0,0 +1,72 @@ +//===-- EpiphanyInstPrinter.h - Convert Epiphany MCInst to assembly syntax --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an Epiphany MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EPIPHANYINSTPRINTER_H +#define LLVM_EPIPHANYINSTPRINTER_H + +#include "MCTargetDesc/EpiphanyMCTargetDesc.h" +#include "Utils/EpiphanyBaseInfo.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCSubtargetInfo.h" + +namespace llvm { + + class MCOperand; + + class EpiphanyInstPrinter : public MCInstPrinter { + public: + EpiphanyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI, const MCSubtargetInfo &STI); + + // Autogenerated by tblgen + void printInstruction(const MCInst *MI, raw_ostream &O); + bool printAliasInstr(const MCInst *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + static const char *getInstructionName(unsigned Opcode); + + void printAddSubImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + + void printBareImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + + void printCondCodeOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + + template + void printOffsetUImm11Operand(const MCInst *MI, unsigned OpNum, raw_ostream &o) { printOffsetUImm11Operand(MI, OpNum, o, MemScale); } + void printOffsetUImm11Operand(const MCInst *MI, unsigned OpNum, raw_ostream &o, int MemScale); + + template + void printLabelOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + + template + void printLogicalImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + + template void + printSImm7ScaledOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + + void printOffsetSImm9Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + + void printFPImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &o); + + void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot); + + bool isStackReg(unsigned RegNo) { + return RegNo == Epiphany::SP; + } + + + }; + +} + +#endif diff --git a/InstPrinter/LLVMBuild.txt b/InstPrinter/LLVMBuild.txt new file mode 100644 index 0000000..ede51e8 --- /dev/null +++ b/InstPrinter/LLVMBuild.txt @@ -0,0 +1,24 @@ +;===- ./lib/Target/Epiphany/InstPrinter/LLVMBuild.txt -----------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = EpiphanyAsmPrinter +parent = Epiphany +required_libraries = EpiphanyUtils MC Support +add_to_library_groups = Epiphany + diff --git a/InstPrinter/Makefile b/InstPrinter/Makefile new file mode 100644 index 0000000..c740e18 --- /dev/null +++ b/InstPrinter/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/Epiphany/AsmPrinter/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMEpiphanyAsmPrinter + +# Hack: we need to include 'main' target directory to grab private headers +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/LLVMBuild.txt b/LLVMBuild.txt new file mode 100644 index 0000000..385b4c7 --- /dev/null +++ b/LLVMBuild.txt @@ -0,0 +1,36 @@ +;===- ./lib/Target/Epiphany/LLVMBuild.txt -----------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[common] +subdirectories = InstPrinter MCTargetDesc TargetInfo Utils + +[component_0] +type = TargetGroup +name = Epiphany +parent = Target +has_asmparser = 0 +has_asmprinter = 1 +has_disassembler = 0 +;has_jit = 1 + +[component_1] +type = Library +name = EpiphanyCodeGen +parent = Epiphany +required_libraries = EpiphanyAsmPrinter EpiphanyDesc EpiphanyInfo AsmPrinter CodeGen Core MC SelectionDAG Support Target +add_to_library_groups = Epiphany + diff --git a/MCTargetDesc/CMakeLists.txt b/MCTargetDesc/CMakeLists.txt new file mode 100644 index 0000000..0a591e4 --- /dev/null +++ b/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,9 @@ +add_llvm_library(LLVMEpiphanyDesc + EpiphanyMCAsmInfo.cpp + EpiphanyMCExpr.cpp + EpiphanyMCTargetDesc.cpp + ) +add_dependencies(LLVMEpiphanyDesc EpiphanyCommonTableGen) + +# Hack: we need to include 'main' target directory to grab private headers +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..) diff --git a/MCTargetDesc/EpiphanyMCAsmInfo.cpp b/MCTargetDesc/EpiphanyMCAsmInfo.cpp new file mode 100644 index 0000000..09fa663 --- /dev/null +++ b/MCTargetDesc/EpiphanyMCAsmInfo.cpp @@ -0,0 +1,41 @@ +//===-- EpiphanyMCAsmInfo.cpp - Epiphany asm properties ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the EpiphanyMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "EpiphanyMCAsmInfo.h" + +using namespace llvm; + +EpiphanyELFMCAsmInfo::EpiphanyELFMCAsmInfo() { + PointerSize = 8; + + // ".comm align is in bytes but .align is pow-2." + AlignmentIsInBytes = false; + + CommentString = "//"; + PrivateGlobalPrefix = ".L"; + Code32Directive = ".code\t32"; + + Data16bitsDirective = "\t.hword\t"; + Data32bitsDirective = "\t.word\t"; + Data64bitsDirective = "\t.xword\t"; + + UseDataRegionDirectives = true; + + WeakRefDirective = "\t.weak\t"; + + HasLEB128 = true; + SupportsDebugInformation = true; + + // Exceptions handling + ExceptionsType = ExceptionHandling::DwarfCFI; +} diff --git a/MCTargetDesc/EpiphanyMCAsmInfo.h b/MCTargetDesc/EpiphanyMCAsmInfo.h new file mode 100644 index 0000000..579886d --- /dev/null +++ b/MCTargetDesc/EpiphanyMCAsmInfo.h @@ -0,0 +1,27 @@ +//==-- EpiphanyMCAsmInfo.h - Epiphany asm properties -------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the EpiphanyMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EPIPHANYTARGETASMINFO_H +#define LLVM_EPIPHANYTARGETASMINFO_H + +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { + + struct EpiphanyELFMCAsmInfo : public MCAsmInfo { + explicit EpiphanyELFMCAsmInfo(); + }; + +} // namespace llvm + +#endif diff --git a/MCTargetDesc/EpiphanyMCExpr.cpp b/MCTargetDesc/EpiphanyMCExpr.cpp new file mode 100644 index 0000000..eb2da8f --- /dev/null +++ b/MCTargetDesc/EpiphanyMCExpr.cpp @@ -0,0 +1,95 @@ +//===-- EpiphanyMCExpr.cpp - Epiphany specific MC expression classes --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation of the assembly expression modifiers +// accepted by the Epiphany architecture (e.g. ":lo12:", ":gottprel_g1:", ...). +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "epiphanymcexpr" +#include "EpiphanyMCExpr.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCELF.h" +#include "llvm/Object/ELF.h" + +using namespace llvm; + +const EpiphanyMCExpr* +EpiphanyMCExpr::Create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx) { + return new (Ctx) EpiphanyMCExpr(Kind, Expr); +} + +void EpiphanyMCExpr::PrintImpl(raw_ostream &OS) const { + switch (Kind) { + default: llvm_unreachable("Invalid kind!"); + case VK_EPIPHANY_LO16: OS << "%low("; break; + case VK_EPIPHANY_HI16: OS << "%high("; break; + } + + const MCExpr *Expr = getSubExpr(); + if (Expr->getKind() != MCExpr::SymbolRef) + OS << '('; + Expr->print(OS); + if (Expr->getKind() != MCExpr::SymbolRef) + OS << ')'; + + switch (Kind) { + case VK_EPIPHANY_LO16: + case VK_EPIPHANY_HI16: OS << ")"; + default: break; + } +} + +bool +EpiphanyMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const { + return getSubExpr()->EvaluateAsRelocatable(Res, *Layout); +} + +static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { + llvm_unreachable("Can't handle nested target expression"); +} + +void EpiphanyMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { +} + +// FIXME: This basically copies MCObjectStreamer::AddValueSymbols. Perhaps +// that method should be made public? +// FIXME: really do above: now that two backends are using it. +static void AddValueSymbolsImpl(const MCExpr *Value, MCAssembler *Asm) { + switch (Value->getKind()) { + case MCExpr::Target: + llvm_unreachable("Can't handle nested target expr!"); + break; + + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(Value); + AddValueSymbolsImpl(BE->getLHS(), Asm); + AddValueSymbolsImpl(BE->getRHS(), Asm); + break; + } + + case MCExpr::SymbolRef: + Asm->getOrCreateSymbolData(cast(Value)->getSymbol()); + break; + + case MCExpr::Unary: + AddValueSymbolsImpl(cast(Value)->getSubExpr(), Asm); + break; + } +} + +void EpiphanyMCExpr::AddValueSymbols(MCAssembler *Asm) const { + AddValueSymbolsImpl(getSubExpr(), Asm); +} diff --git a/MCTargetDesc/EpiphanyMCExpr.h b/MCTargetDesc/EpiphanyMCExpr.h new file mode 100644 index 0000000..d68f520 --- /dev/null +++ b/MCTargetDesc/EpiphanyMCExpr.h @@ -0,0 +1,82 @@ +//==- EpiphanyMCExpr.h - Epiphany specific MC expression classes --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Epiphany-specific MCExprs, used for modifiers like +// ":lo12:" or ":gottprel_g1:". +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EPIPHANYMCEXPR_H +#define LLVM_EPIPHANYMCEXPR_H + +#include "llvm/MC/MCExpr.h" + +namespace llvm { + +class EpiphanyMCExpr : public MCTargetExpr { +public: + enum VariantKind { + VK_EPIPHANY_None, + VK_EPIPHANY_LO16, // :lo12: + VK_EPIPHANY_HI16, // :lo12: + }; + +private: + const VariantKind Kind; + const MCExpr *Expr; + + explicit EpiphanyMCExpr(VariantKind _Kind, const MCExpr *_Expr) + : Kind(_Kind), Expr(_Expr) {} + +public: + /// @name Construction + /// @{ + + static const EpiphanyMCExpr *Create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx); + + static const EpiphanyMCExpr *CreateLo16(const MCExpr *Expr, MCContext &Ctx) { + return Create(VK_EPIPHANY_LO16, Expr, Ctx); + } + static const EpiphanyMCExpr *CreateHi16(const MCExpr *Expr, MCContext &Ctx) { + return Create(VK_EPIPHANY_HI16, Expr, Ctx); + } + + /// @} + /// @name Accessors + /// @{ + + /// getOpcode - Get the kind of this expression. + VariantKind getKind() const { return Kind; } + + /// getSubExpr - Get the child of this expression. + const MCExpr *getSubExpr() const { return Expr; } + + /// @} + + void PrintImpl(raw_ostream &OS) const; + bool EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const; + void AddValueSymbols(MCAssembler *) const; + const MCSection *FindAssociatedSection() const { + return getSubExpr()->FindAssociatedSection(); + } + + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const; + + static bool classof(const MCExpr *E) { + return E->getKind() == MCExpr::Target; + } + + static bool classof(const EpiphanyMCExpr *) { return true; } + +}; +} // end namespace llvm + +#endif diff --git a/MCTargetDesc/EpiphanyMCTargetDesc.cpp b/MCTargetDesc/EpiphanyMCTargetDesc.cpp new file mode 100644 index 0000000..6b8bc0b --- /dev/null +++ b/MCTargetDesc/EpiphanyMCTargetDesc.cpp @@ -0,0 +1,175 @@ +//===-- EpiphanyMCTargetDesc.cpp - Epiphany Target Descriptions -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Epiphany specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "EpiphanyMCTargetDesc.h" +//#include "EpiphanyELFStreamer.h" +#include "EpiphanyMCAsmInfo.h" +#include "InstPrinter/EpiphanyInstPrinter.h" +#include "llvm/ADT/APInt.h" +#include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCInstrAnalysis.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/ErrorHandling.h" + +#define GET_REGINFO_MC_DESC +#include "EpiphanyGenRegisterInfo.inc" + +#define GET_INSTRINFO_MC_DESC +#include "EpiphanyGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "EpiphanyGenSubtargetInfo.inc" + +using namespace llvm; + +MCSubtargetInfo *Epiphany_MC::createEpiphanyMCSubtargetInfo(StringRef TT, + StringRef CPU, + StringRef FS) { + MCSubtargetInfo *X = new MCSubtargetInfo(); + InitEpiphanyMCSubtargetInfo(X, TT, CPU, ""); + return X; +} + + +static MCInstrInfo *createEpiphanyMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitEpiphanyMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createEpiphanyMCRegisterInfo(StringRef Triple) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitEpiphanyMCRegisterInfo(X, Epiphany::LR); + return X; +} + +static MCAsmInfo *createEpiphanyMCAsmInfo(const Target &T, StringRef TT) { + Triple TheTriple(TT); + + MCAsmInfo *MAI = new EpiphanyELFMCAsmInfo(); + MachineLocation Dst(MachineLocation::VirtualFP); + MachineLocation Src(Epiphany::SP, 0); + MAI->addInitialFrameState(0, Dst, Src); + + return MAI; +} + +static MCCodeGenInfo *createEpiphanyMCCodeGenInfo(StringRef TT, Reloc::Model RM, + CodeModel::Model CM, + CodeGenOpt::Level OL) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + RM = Reloc::Static; + CM = CodeModel::Small; + X->InitMCCodeGenInfo(RM, CM, OL); + return X; +} + + +static MCInstPrinter *createEpiphanyMCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI) { + if (SyntaxVariant == 0) + return new EpiphanyInstPrinter(MAI, MII, MRI, STI); + return 0; +} + +namespace { + +class EpiphanyMCInstrAnalysis : public MCInstrAnalysis { +public: + EpiphanyMCInstrAnalysis(const MCInstrInfo *Info) : MCInstrAnalysis(Info) {} + + virtual bool isUnconditionalBranch(const MCInst &Inst) const { + if (Inst.getOpcode() == Epiphany::Bcc + && Inst.getOperand(0).getImm() == EpiphanyCC::AL) + return true; + return MCInstrAnalysis::isUnconditionalBranch(Inst); + } + + virtual bool isConditionalBranch(const MCInst &Inst) const { + if (Inst.getOpcode() == Epiphany::Bcc + && Inst.getOperand(0).getImm() == EpiphanyCC::AL) + return false; + return MCInstrAnalysis::isConditionalBranch(Inst); + } + + uint64_t evaluateBranch(const MCInst &Inst, uint64_t Addr, + uint64_t Size) const { + unsigned LblOperand = Inst.getOpcode() == Epiphany::Bcc ? 1 : 0; + // FIXME: We only handle PCRel branches for now. + if (Info->get(Inst.getOpcode()).OpInfo[LblOperand].OperandType + != MCOI::OPERAND_PCREL) + return -1ULL; + + int64_t Imm = Inst.getOperand(LblOperand).getImm(); + + return Addr + Imm; + } +}; + +} + +static MCInstrAnalysis *createEpiphanyMCInstrAnalysis(const MCInstrInfo *Info) { + return new EpiphanyMCInstrAnalysis(Info); +} + + + +extern "C" void LLVMInitializeEpiphanyTargetMC() { + // Register the MC asm info. + RegisterMCAsmInfoFn A(TheEpiphanyTarget, createEpiphanyMCAsmInfo); + + // Register the MC codegen info. + TargetRegistry::RegisterMCCodeGenInfo(TheEpiphanyTarget, + createEpiphanyMCCodeGenInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(TheEpiphanyTarget, + createEpiphanyMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(TheEpiphanyTarget, + createEpiphanyMCRegisterInfo); + + // Register the MC subtarget info. + using Epiphany_MC::createEpiphanyMCSubtargetInfo; + TargetRegistry::RegisterMCSubtargetInfo(TheEpiphanyTarget, + createEpiphanyMCSubtargetInfo); + + // Register the MC instruction analyzer. + TargetRegistry::RegisterMCInstrAnalysis(TheEpiphanyTarget, + createEpiphanyMCInstrAnalysis); + + //// Register the MC Code Emitter + //TargetRegistry::RegisterMCCodeEmitter(TheEpiphanyTarget, + // createEpiphanyMCCodeEmitter); + + //// Register the asm backend. + //TargetRegistry::RegisterMCAsmBackend(TheEpiphanyTarget, + // createEpiphanyAsmBackend); + + //// Register the object streamer. + //TargetRegistry::RegisterMCObjectStreamer(TheEpiphanyTarget, + // createMCStreamer); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(TheEpiphanyTarget, + createEpiphanyMCInstPrinter); +} diff --git a/MCTargetDesc/EpiphanyMCTargetDesc.h b/MCTargetDesc/EpiphanyMCTargetDesc.h new file mode 100644 index 0000000..ce84098 --- /dev/null +++ b/MCTargetDesc/EpiphanyMCTargetDesc.h @@ -0,0 +1,65 @@ +//===-- EpiphanyMCTargetDesc.h - Epiphany Target Descriptions -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Epiphany specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EPIPHANYMCTARGETDESC_H +#define LLVM_EPIPHANYMCTARGETDESC_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectWriter; +class MCRegisterInfo; +class MCSubtargetInfo; +class StringRef; +class Target; +class raw_ostream; + +extern Target TheEpiphanyTarget; + +namespace Epiphany_MC { + MCSubtargetInfo *createEpiphanyMCSubtargetInfo(StringRef TT, StringRef CPU, + StringRef FS); +} + +//MCCodeEmitter *createEpiphanyMCCodeEmitter(const MCInstrInfo &MCII, +// const MCRegisterInfo &MRI, +// const MCSubtargetInfo &STI, +// MCContext &Ctx); + +//MCObjectWriter *createEpiphanyELFObjectWriter(raw_ostream &OS, +// uint8_t OSABI); + +//MCAsmBackend *createEpiphanyAsmBackend(const Target &T, StringRef TT, +// StringRef CPU); + +} // End llvm namespace + +// Defines symbolic names for Epiphany registers. This defines a mapping from +// register name to register number. +// +#define GET_REGINFO_ENUM +#include "EpiphanyGenRegisterInfo.inc" + +// Defines symbolic names for the Epiphany instructions. +// +#define GET_INSTRINFO_ENUM +#include "EpiphanyGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "EpiphanyGenSubtargetInfo.inc" + +#endif diff --git a/MCTargetDesc/LLVMBuild.txt b/MCTargetDesc/LLVMBuild.txt new file mode 100644 index 0000000..ce34d13 --- /dev/null +++ b/MCTargetDesc/LLVMBuild.txt @@ -0,0 +1,24 @@ +;===- ./lib/Target/Epiphany/MCTargetDesc/LLVMBuild.txt ----------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = EpiphanyDesc +parent = Epiphany +required_libraries = EpiphanyAsmPrinter EpiphanyInfo MC Support +add_to_library_groups = Epiphany + diff --git a/MCTargetDesc/Makefile b/MCTargetDesc/Makefile new file mode 100644 index 0000000..dcd532e --- /dev/null +++ b/MCTargetDesc/Makefile @@ -0,0 +1,16 @@ +##===- lib/Target/Epiphany/TargetDesc/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME = LLVMEpiphanyDesc + +# Hack: we need to include 'main' target directory to grab private headers +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a4c1bd0 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +##===- lib/Target/Epiphany/Makefile -------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMEpiphanyCodeGen +TARGET = Epiphany + +# Make sure that tblgen is run, first thing. +BUILT_SOURCES = EpiphanyGenAsmMatcher.inc \ + EpiphanyGenAsmWriter.inc \ + EpiphanyGenCallingConv.inc \ + EpiphanyGenDAGISel.inc \ + EpiphanyGenDisassemblerTables.inc \ + EpiphanyGenInstrInfo.inc \ + EpiphanyGenMCCodeEmitter.inc \ + EpiphanyGenMCPseudoLowering.inc \ + EpiphanyGenRegisterInfo.inc \ + EpiphanyGenSubtargetInfo.inc + +DIRS = InstPrinter AsmParser Disassembler TargetInfo MCTargetDesc Utils + +include $(LEVEL)/Makefile.common + + diff --git a/README.md b/README.md index 126232e..0527a80 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ Epiphany ======== -the actual epiphany backend +the actual epiphany backend, based on the AArch64 backend diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..050aeb8 --- /dev/null +++ b/README.txt @@ -0,0 +1,2 @@ +This file will contain changes that need to be made before Epiphany can become an +officially supported target. Currently a placeholder. diff --git a/TargetInfo/CMakeLists.txt b/TargetInfo/CMakeLists.txt new file mode 100644 index 0000000..35f0b2b --- /dev/null +++ b/TargetInfo/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMEpiphanyInfo + EpiphanyTargetInfo.cpp + ) + +add_dependencies(LLVMEpiphanyInfo EpiphanyCommonTableGen) diff --git a/TargetInfo/EpiphanyTargetInfo.cpp b/TargetInfo/EpiphanyTargetInfo.cpp new file mode 100644 index 0000000..5b7aded --- /dev/null +++ b/TargetInfo/EpiphanyTargetInfo.cpp @@ -0,0 +1,24 @@ +//===-- EpiphanyTargetInfo.cpp - Epiphany Target Implementation -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the key registration step for the architecture. +// +//===----------------------------------------------------------------------===// + +#include "Epiphany.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheEpiphanyTarget; + +extern "C" void LLVMInitializeEpiphanyTargetInfo() { + RegisterTarget + X(TheEpiphanyTarget, "epiphany", "Epiphany"); +} diff --git a/TargetInfo/LLVMBuild.txt b/TargetInfo/LLVMBuild.txt new file mode 100644 index 0000000..75f222d --- /dev/null +++ b/TargetInfo/LLVMBuild.txt @@ -0,0 +1,24 @@ +;===- ./lib/Target/Epiphany/TargetInfo/LLVMBuild.txt ------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = EpiphanyInfo +parent = Epiphany +required_libraries = MC Support Target +add_to_library_groups = Epiphany + diff --git a/TargetInfo/Makefile b/TargetInfo/Makefile new file mode 100644 index 0000000..8a8da98 --- /dev/null +++ b/TargetInfo/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/Epiphany/TargetInfo/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMEpiphanyInfo + +# Hack: we need to include 'main' target directory to grab private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/Utils/CMakeLists.txt b/Utils/CMakeLists.txt new file mode 100644 index 0000000..707b23c --- /dev/null +++ b/Utils/CMakeLists.txt @@ -0,0 +1,5 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMEpiphanyUtils + EpiphanyBaseInfo.cpp + ) diff --git a/Utils/EpiphanyBaseInfo.cpp b/Utils/EpiphanyBaseInfo.cpp new file mode 100644 index 0000000..4dfc3bc --- /dev/null +++ b/Utils/EpiphanyBaseInfo.cpp @@ -0,0 +1,71 @@ +//===-- EpiphanyBaseInfo.cpp - Epiphany Base encoding information------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides basic encoding and assembly information for Epiphany. +// +//===----------------------------------------------------------------------===// +#include "EpiphanyBaseInfo.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Regex.h" + +using namespace llvm; + +bool EpiphanyImms::isFPImm(const APFloat &Val, uint32_t &Imm8Bits) { + const fltSemantics &Sem = Val.getSemantics(); + unsigned FracBits = APFloat::semanticsPrecision(Sem) - 1; + + uint32_t ExpMask; + switch (FracBits) { + case 10: // IEEE half-precision + ExpMask = 0x1f; + break; + case 23: // IEEE single-precision + ExpMask = 0xff; + break; + case 52: // IEEE double-precision + ExpMask = 0x7ff; + break; + case 112: // IEEE quad-precision + // No immediates are valid for double precision. + return false; + default: + llvm_unreachable("Only half, single and double precision supported"); + } + + uint32_t ExpStart = FracBits; + uint64_t FracMask = (1ULL << FracBits) - 1; + + uint32_t Sign = Val.isNegative(); + + uint64_t Bits= Val.bitcastToAPInt().getLimitedValue(); + uint64_t Fraction = Bits & FracMask; + int32_t Exponent = ((Bits >> ExpStart) & ExpMask); + Exponent -= ExpMask >> 1; + + // S[d] = imm8<7>:NOT(imm8<6>):Replicate(imm8<6>, 5):imm8<5:0>:Zeros(19) + // D[d] = imm8<7>:NOT(imm8<6>):Replicate(imm8<6>, 8):imm8<5:0>:Zeros(48) + // This translates to: only 4 bits of fraction; -3 <= exp <= 4. + uint64_t A64FracStart = FracBits - 4; + uint64_t A64FracMask = 0xf; + + // Are there too many fraction bits? + if (Fraction & ~(A64FracMask << A64FracStart)) + return false; + + if (Exponent < -3 || Exponent > 4) + return false; + + uint32_t PackedFraction = (Fraction >> A64FracStart) & A64FracMask; + uint32_t PackedExp = (Exponent + 7) & 0x7; + + Imm8Bits = (Sign << 7) | (PackedExp << 4) | PackedFraction; + return true; +} diff --git a/Utils/EpiphanyBaseInfo.h b/Utils/EpiphanyBaseInfo.h new file mode 100644 index 0000000..0a2c192 --- /dev/null +++ b/Utils/EpiphanyBaseInfo.h @@ -0,0 +1,102 @@ +//===-- EpiphanyBaseInfo.h - Top level definitions for Epiphany- --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains small standalone helper functions and enum definitions for +// the Epiphany 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_EPIPHANY_BASEINFO_H +#define LLVM_EPIPHANY_BASEINFO_H + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + +// // Enums corresponding to Epiphany condition codes +namespace EpiphanyCC { + // The CondCodes constants map directly to the 4-bit encoding of the + // condition field for predicated instructions. + enum CondCodes { + EQ = 0, + NE, + GTU, + GTEU, + LTEU, + LTU, + GT, + GTE, + LT, + LTE, + BEQ, + BNE, + BLT, + BLTE, + AL, // unconditional, always + L, // link + Invalid + }; + +} // namespace EpiphanyCC + +inline static const char *A64CondCodeToString(EpiphanyCC::CondCodes CC) { + switch (CC) { + default: llvm_unreachable("Unknown condition code"); + case EpiphanyCC::EQ: return "eq"; + case EpiphanyCC::NE: return "ne"; + case EpiphanyCC::GTU: return "gtu"; + case EpiphanyCC::GTEU: return "gteu"; + case EpiphanyCC::LTEU: return "lteu"; + case EpiphanyCC::LTU: return "ltu"; + case EpiphanyCC::GT: return "gt"; + case EpiphanyCC::GTE: return "gte"; + case EpiphanyCC::LT: return "lt"; + case EpiphanyCC::LTE: return "lte"; + case EpiphanyCC::BEQ: return "beq"; + case EpiphanyCC::BNE: return "bne"; + case EpiphanyCC::BLT: return "blt"; + case EpiphanyCC::BLTE: return "blte"; + case EpiphanyCC::AL: return "al"; // unconditional, always + case EpiphanyCC::L: return "l"; // link + + } +} +namespace EpiphanyII { + + enum TOF { + //===--------------------------------------------------------------===// + // Epiphany Specific MachineOperand flags. + + MO_NO_FLAG, + + // LO/HI reloc, only for symbols + MO_LO16, + MO_HI16 + }; +} + +class APFloat; + +namespace EpiphanyImms { + bool isFPImm(const APFloat &Val, uint32_t &Imm8Bits); + + inline bool isFPImm(const APFloat &Val) { + uint32_t Imm8; + return isFPImm(Val, Imm8); + } + +} + +} // end namespace llvm; + +#endif diff --git a/Utils/LLVMBuild.txt b/Utils/LLVMBuild.txt new file mode 100644 index 0000000..f06add2 --- /dev/null +++ b/Utils/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/Epiphany6/Utils/LLVMBuild.txt ----------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = EpiphanyUtils +parent = Epiphany +required_libraries = Core Support +add_to_library_groups = Epiphany diff --git a/Utils/Makefile b/Utils/Makefile new file mode 100644 index 0000000..b90a4b6 --- /dev/null +++ b/Utils/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/Epiphany/Utils/Makefile -------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMEpiphanyUtils + +# Hack: we need to include 'main' Epiphany target directory to grab private headers +#CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common