diff options
author | Ed Schouten <ed@FreeBSD.org> | 2009-06-02 17:52:33 +0000 |
---|---|---|
committer | Ed Schouten <ed@FreeBSD.org> | 2009-06-02 17:52:33 +0000 |
commit | 009b1c42aa6266385f2c37e227516b24077e6dd7 (patch) | |
tree | 64ba909838c23261cace781ece27d106134ea451 /lib/Target/Alpha | |
download | src-test2-009b1c42aa6266385f2c37e227516b24077e6dd7.tar.gz src-test2-009b1c42aa6266385f2c37e227516b24077e6dd7.zip |
Notes
Diffstat (limited to 'lib/Target/Alpha')
31 files changed, 5804 insertions, 0 deletions
diff --git a/lib/Target/Alpha/Alpha.h b/lib/Target/Alpha/Alpha.h new file mode 100644 index 000000000000..281517614935 --- /dev/null +++ b/lib/Target/Alpha/Alpha.h @@ -0,0 +1,51 @@ +//===-- Alpha.h - Top-level interface for Alpha 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 +// Alpha back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef TARGET_ALPHA_H +#define TARGET_ALPHA_H + +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + + class AlphaTargetMachine; + class FunctionPass; + class MachineCodeEmitter; + class raw_ostream; + + FunctionPass *createAlphaISelDag(AlphaTargetMachine &TM); + FunctionPass *createAlphaCodePrinterPass(raw_ostream &OS, + TargetMachine &TM, + CodeGenOpt::Level OptLevel, + bool Verbose); + FunctionPass *createAlphaPatternInstructionSelector(TargetMachine &TM); + FunctionPass *createAlphaCodeEmitterPass(AlphaTargetMachine &TM, + MachineCodeEmitter &MCE); + FunctionPass *createAlphaJITCodeEmitterPass(AlphaTargetMachine &TM, + JITCodeEmitter &JCE); + FunctionPass *createAlphaLLRPPass(AlphaTargetMachine &tm); + FunctionPass *createAlphaBranchSelectionPass(); + +} // end namespace llvm; + +// Defines symbolic names for Alpha registers. This defines a mapping from +// register name to register number. +// +#include "AlphaGenRegisterNames.inc" + +// Defines symbolic names for the Alpha instructions. +// +#include "AlphaGenInstrNames.inc" + +#endif diff --git a/lib/Target/Alpha/Alpha.td b/lib/Target/Alpha/Alpha.td new file mode 100644 index 000000000000..e3748c6a09f3 --- /dev/null +++ b/lib/Target/Alpha/Alpha.td @@ -0,0 +1,66 @@ +//===- Alpha.td - Describe the Alpha Target Machine --------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +// Get the target-independent interfaces which we are implementing... +// +include "llvm/Target/Target.td" + +//Alpha is little endian + +//===----------------------------------------------------------------------===// +// Subtarget Features +//===----------------------------------------------------------------------===// + +def FeatureCIX : SubtargetFeature<"cix", "HasCT", "true", + "Enable CIX extentions">; + +//===----------------------------------------------------------------------===// +// Register File Description +//===----------------------------------------------------------------------===// + +include "AlphaRegisterInfo.td" + +//===----------------------------------------------------------------------===// +// Schedule Description +//===----------------------------------------------------------------------===// + +include "AlphaSchedule.td" + +//===----------------------------------------------------------------------===// +// Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "AlphaInstrInfo.td" + +def AlphaInstrInfo : InstrInfo { + // Define how we want to layout our target-specific information field. + // let TSFlagsFields = []; + // let TSFlagsShifts = []; +} + +//===----------------------------------------------------------------------===// +// Alpha Processor Definitions +//===----------------------------------------------------------------------===// + +def : Processor<"generic", Alpha21264Itineraries, []>; +def : Processor<"ev6" , Alpha21264Itineraries, []>; +def : Processor<"ev67" , Alpha21264Itineraries, [FeatureCIX]>; + +//===----------------------------------------------------------------------===// +// The Alpha Target +//===----------------------------------------------------------------------===// + + +def Alpha : Target { + // Pull in Instruction Info: + let InstructionSet = AlphaInstrInfo; +} diff --git a/lib/Target/Alpha/AlphaBranchSelector.cpp b/lib/Target/Alpha/AlphaBranchSelector.cpp new file mode 100644 index 000000000000..aca8ca734897 --- /dev/null +++ b/lib/Target/Alpha/AlphaBranchSelector.cpp @@ -0,0 +1,67 @@ +//===-- AlphaBranchSelector.cpp - Convert Pseudo branchs ----------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Replace Pseudo COND_BRANCH_* with their appropriate real branch +// Simplified version of the PPC Branch Selector +// +//===----------------------------------------------------------------------===// + +#include "Alpha.h" +#include "AlphaInstrInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetAsmInfo.h" +using namespace llvm; + +namespace { + struct VISIBILITY_HIDDEN AlphaBSel : public MachineFunctionPass { + static char ID; + AlphaBSel() : MachineFunctionPass(&ID) {} + + virtual bool runOnMachineFunction(MachineFunction &Fn); + + virtual const char *getPassName() const { + return "Alpha Branch Selection"; + } + }; + char AlphaBSel::ID = 0; +} + +/// createAlphaBranchSelectionPass - returns an instance of the Branch Selection +/// Pass +/// +FunctionPass *llvm::createAlphaBranchSelectionPass() { + return new AlphaBSel(); +} + +bool AlphaBSel::runOnMachineFunction(MachineFunction &Fn) { + + for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; + ++MFI) { + MachineBasicBlock *MBB = MFI; + + for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end(); + MBBI != EE; ++MBBI) { + if (MBBI->getOpcode() == Alpha::COND_BRANCH_I || + MBBI->getOpcode() == Alpha::COND_BRANCH_F) { + + // condbranch operands: + // 0. bc opcode + // 1. reg + // 2. target MBB + const TargetInstrInfo *TII = Fn.getTarget().getInstrInfo(); + MBBI->setDesc(TII->get(MBBI->getOperand(0).getImm())); + } + } + } + + return true; +} + diff --git a/lib/Target/Alpha/AlphaCodeEmitter.cpp b/lib/Target/Alpha/AlphaCodeEmitter.cpp new file mode 100644 index 000000000000..f50f007c2076 --- /dev/null +++ b/lib/Target/Alpha/AlphaCodeEmitter.cpp @@ -0,0 +1,242 @@ +//===-- Alpha/AlphaCodeEmitter.cpp - Convert Alpha code to machine code ---===// +// +// 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 pass that transforms the Alpha machine instructions +// into relocatable machine code. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "alpha-emitter" +#include "AlphaTargetMachine.h" +#include "AlphaRelocations.h" +#include "Alpha.h" +#include "llvm/PassManager.h" +#include "llvm/CodeGen/MachineCodeEmitter.h" +#include "llvm/CodeGen/JITCodeEmitter.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Function.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +using namespace llvm; + +namespace { + + class AlphaCodeEmitter { + MachineCodeEmitter &MCE; + public: + AlphaCodeEmitter(MachineCodeEmitter &mce) : MCE(mce) {} + + /// getBinaryCodeForInstr - This function, generated by the + /// CodeEmitterGenerator using TableGen, produces the binary encoding for + /// machine instructions. + + unsigned getBinaryCodeForInstr(const MachineInstr &MI); + + /// getMachineOpValue - evaluates the MachineOperand of a given MachineInstr + + unsigned getMachineOpValue(const MachineInstr &MI, + const MachineOperand &MO); + }; + + template <class CodeEmitter> + class VISIBILITY_HIDDEN Emitter : public MachineFunctionPass, + public AlphaCodeEmitter + { + const AlphaInstrInfo *II; + TargetMachine &TM; + CodeEmitter &MCE; + + public: + static char ID; + explicit Emitter(TargetMachine &tm, CodeEmitter &mce) + : MachineFunctionPass(&ID), AlphaCodeEmitter(mce), + II(0), TM(tm), MCE(mce) {} + Emitter(TargetMachine &tm, CodeEmitter &mce, const AlphaInstrInfo& ii) + : MachineFunctionPass(&ID), AlphaCodeEmitter(mce), + II(&ii), TM(tm), MCE(mce) {} + + bool runOnMachineFunction(MachineFunction &MF); + + virtual const char *getPassName() const { + return "Alpha Machine Code Emitter"; + } + + void emitInstruction(const MachineInstr &MI); + + private: + void emitBasicBlock(MachineBasicBlock &MBB); + }; + + template <class CodeEmitter> + char Emitter<CodeEmitter>::ID = 0; +} + +/// createAlphaCodeEmitterPass - Return a pass that emits the collected Alpha +/// code to the specified MCE object. + +FunctionPass *llvm::createAlphaCodeEmitterPass(AlphaTargetMachine &TM, + MachineCodeEmitter &MCE) { + return new Emitter<MachineCodeEmitter>(TM, MCE); +} + +FunctionPass *llvm::createAlphaJITCodeEmitterPass(AlphaTargetMachine &TM, + JITCodeEmitter &JCE) { + return new Emitter<JITCodeEmitter>(TM, JCE); +} + +template <class CodeEmitter> +bool Emitter<CodeEmitter>::runOnMachineFunction(MachineFunction &MF) { + II = ((AlphaTargetMachine&)MF.getTarget()).getInstrInfo(); + + do { + MCE.startFunction(MF); + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) + emitBasicBlock(*I); + } while (MCE.finishFunction(MF)); + + return false; +} + +template <class CodeEmitter> +void Emitter<CodeEmitter>::emitBasicBlock(MachineBasicBlock &MBB) { + MCE.StartMachineBasicBlock(&MBB); + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); + I != E; ++I) { + const MachineInstr &MI = *I; + switch(MI.getOpcode()) { + default: + MCE.emitWordLE(getBinaryCodeForInstr(*I)); + break; + case Alpha::ALTENT: + case Alpha::PCLABEL: + case Alpha::MEMLABEL: + case TargetInstrInfo::IMPLICIT_DEF: + break; //skip these + } + } +} + +static unsigned getAlphaRegNumber(unsigned Reg) { + switch (Reg) { + case Alpha::R0 : case Alpha::F0 : return 0; + case Alpha::R1 : case Alpha::F1 : return 1; + case Alpha::R2 : case Alpha::F2 : return 2; + case Alpha::R3 : case Alpha::F3 : return 3; + case Alpha::R4 : case Alpha::F4 : return 4; + case Alpha::R5 : case Alpha::F5 : return 5; + case Alpha::R6 : case Alpha::F6 : return 6; + case Alpha::R7 : case Alpha::F7 : return 7; + case Alpha::R8 : case Alpha::F8 : return 8; + case Alpha::R9 : case Alpha::F9 : return 9; + case Alpha::R10 : case Alpha::F10 : return 10; + case Alpha::R11 : case Alpha::F11 : return 11; + case Alpha::R12 : case Alpha::F12 : return 12; + case Alpha::R13 : case Alpha::F13 : return 13; + case Alpha::R14 : case Alpha::F14 : return 14; + case Alpha::R15 : case Alpha::F15 : return 15; + case Alpha::R16 : case Alpha::F16 : return 16; + case Alpha::R17 : case Alpha::F17 : return 17; + case Alpha::R18 : case Alpha::F18 : return 18; + case Alpha::R19 : case Alpha::F19 : return 19; + case Alpha::R20 : case Alpha::F20 : return 20; + case Alpha::R21 : case Alpha::F21 : return 21; + case Alpha::R22 : case Alpha::F22 : return 22; + case Alpha::R23 : case Alpha::F23 : return 23; + case Alpha::R24 : case Alpha::F24 : return 24; + case Alpha::R25 : case Alpha::F25 : return 25; + case Alpha::R26 : case Alpha::F26 : return 26; + case Alpha::R27 : case Alpha::F27 : return 27; + case Alpha::R28 : case Alpha::F28 : return 28; + case Alpha::R29 : case Alpha::F29 : return 29; + case Alpha::R30 : case Alpha::F30 : return 30; + case Alpha::R31 : case Alpha::F31 : return 31; + default: + assert(0 && "Unhandled reg"); + abort(); + } +} + +unsigned AlphaCodeEmitter::getMachineOpValue(const MachineInstr &MI, + const MachineOperand &MO) { + + unsigned rv = 0; // Return value; defaults to 0 for unhandled cases + // or things that get fixed up later by the JIT. + + if (MO.isReg()) { + rv = getAlphaRegNumber(MO.getReg()); + } else if (MO.isImm()) { + rv = MO.getImm(); + } else if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) { + DOUT << MO << " is a relocated op for " << MI << "\n"; + unsigned Reloc = 0; + int Offset = 0; + bool useGOT = false; + switch (MI.getOpcode()) { + case Alpha::BSR: + Reloc = Alpha::reloc_bsr; + break; + case Alpha::LDLr: + case Alpha::LDQr: + case Alpha::LDBUr: + case Alpha::LDWUr: + case Alpha::LDSr: + case Alpha::LDTr: + case Alpha::LDAr: + case Alpha::STQr: + case Alpha::STLr: + case Alpha::STWr: + case Alpha::STBr: + case Alpha::STSr: + case Alpha::STTr: + Reloc = Alpha::reloc_gprellow; + break; + case Alpha::LDAHr: + Reloc = Alpha::reloc_gprelhigh; + break; + case Alpha::LDQl: + Reloc = Alpha::reloc_literal; + useGOT = true; + break; + case Alpha::LDAg: + case Alpha::LDAHg: + Reloc = Alpha::reloc_gpdist; + Offset = MI.getOperand(3).getImm(); + break; + default: + assert(0 && "unknown relocatable instruction"); + abort(); + } + if (MO.isGlobal()) + MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), + Reloc, MO.getGlobal(), Offset, + isa<Function>(MO.getGlobal()), + useGOT)); + else if (MO.isSymbol()) + MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(), + Reloc, MO.getSymbolName(), + Offset, true)); + else + MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(), + Reloc, MO.getIndex(), Offset)); + } else if (MO.isMBB()) { + MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(), + Alpha::reloc_bsr, MO.getMBB())); + }else { + cerr << "ERROR: Unknown type of MachineOperand: " << MO << "\n"; + abort(); + } + + return rv; +} + +#include "AlphaGenCodeEmitter.inc" + + diff --git a/lib/Target/Alpha/AlphaISelDAGToDAG.cpp b/lib/Target/Alpha/AlphaISelDAGToDAG.cpp new file mode 100644 index 000000000000..affcd3e7fec8 --- /dev/null +++ b/lib/Target/Alpha/AlphaISelDAGToDAG.cpp @@ -0,0 +1,553 @@ +//===-- AlphaISelDAGToDAG.cpp - Alpha pattern matching inst selector ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a pattern matching instruction selector for Alpha, +// converting from a legalized dag to a Alpha dag. +// +//===----------------------------------------------------------------------===// + +#include "Alpha.h" +#include "AlphaTargetMachine.h" +#include "AlphaISelLowering.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/GlobalValue.h" +#include "llvm/Intrinsics.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +#include <algorithm> +using namespace llvm; + +namespace { + + //===--------------------------------------------------------------------===// + /// AlphaDAGToDAGISel - Alpha specific code to select Alpha machine + /// instructions for SelectionDAG operations. + class AlphaDAGToDAGISel : public SelectionDAGISel { + static const int64_t IMM_LOW = -32768; + static const int64_t IMM_HIGH = 32767; + static const int64_t IMM_MULT = 65536; + static const int64_t IMM_FULLHIGH = IMM_HIGH + IMM_HIGH * IMM_MULT; + static const int64_t IMM_FULLLOW = IMM_LOW + IMM_LOW * IMM_MULT; + + static int64_t get_ldah16(int64_t x) { + int64_t y = x / IMM_MULT; + if (x % IMM_MULT > IMM_HIGH) + ++y; + return y; + } + + static int64_t get_lda16(int64_t x) { + return x - get_ldah16(x) * IMM_MULT; + } + + /// get_zapImm - Return a zap mask if X is a valid immediate for a zapnot + /// instruction (if not, return 0). Note that this code accepts partial + /// zap masks. For example (and LHS, 1) is a valid zap, as long we know + /// that the bits 1-7 of LHS are already zero. If LHS is non-null, we are + /// in checking mode. If LHS is null, we assume that the mask has already + /// been validated before. + uint64_t get_zapImm(SDValue LHS, uint64_t Constant) { + uint64_t BitsToCheck = 0; + unsigned Result = 0; + for (unsigned i = 0; i != 8; ++i) { + if (((Constant >> 8*i) & 0xFF) == 0) { + // nothing to do. + } else { + Result |= 1 << i; + if (((Constant >> 8*i) & 0xFF) == 0xFF) { + // If the entire byte is set, zapnot the byte. + } else if (LHS.getNode() == 0) { + // Otherwise, if the mask was previously validated, we know its okay + // to zapnot this entire byte even though all the bits aren't set. + } else { + // Otherwise we don't know that the it's okay to zapnot this entire + // byte. Only do this iff we can prove that the missing bits are + // already null, so the bytezap doesn't need to really null them. + BitsToCheck |= ~Constant & (0xFF << 8*i); + } + } + } + + // If there are missing bits in a byte (for example, X & 0xEF00), check to + // see if the missing bits (0x1000) are already known zero if not, the zap + // isn't okay to do, as it won't clear all the required bits. + if (BitsToCheck && + !CurDAG->MaskedValueIsZero(LHS, + APInt(LHS.getValueSizeInBits(), + BitsToCheck))) + return 0; + + return Result; + } + + static uint64_t get_zapImm(uint64_t x) { + unsigned build = 0; + for(int i = 0; i != 8; ++i) { + if ((x & 0x00FF) == 0x00FF) + build |= 1 << i; + else if ((x & 0x00FF) != 0) + return 0; + x >>= 8; + } + return build; + } + + + static uint64_t getNearPower2(uint64_t x) { + if (!x) return 0; + unsigned at = CountLeadingZeros_64(x); + uint64_t complow = 1 << (63 - at); + uint64_t comphigh = 1 << (64 - at); + //cerr << x << ":" << complow << ":" << comphigh << "\n"; + if (abs(complow - x) <= abs(comphigh - x)) + return complow; + else + return comphigh; + } + + static bool chkRemNearPower2(uint64_t x, uint64_t r, bool swap) { + uint64_t y = getNearPower2(x); + if (swap) + return (y - x) == r; + else + return (x - y) == r; + } + + static bool isFPZ(SDValue N) { + ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N); + return (CN && (CN->getValueAPF().isZero())); + } + static bool isFPZn(SDValue N) { + ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N); + return (CN && CN->getValueAPF().isNegZero()); + } + static bool isFPZp(SDValue N) { + ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N); + return (CN && CN->getValueAPF().isPosZero()); + } + + public: + explicit AlphaDAGToDAGISel(AlphaTargetMachine &TM) + : SelectionDAGISel(TM) + {} + + /// getI64Imm - Return a target constant with the specified value, of type + /// i64. + inline SDValue getI64Imm(int64_t Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i64); + } + + // Select - Convert the specified operand from a target-independent to a + // target-specific node if it hasn't already been changed. + SDNode *Select(SDValue Op); + + /// InstructionSelect - This callback is invoked by + /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. + virtual void InstructionSelect(); + + virtual const char *getPassName() const { + return "Alpha DAG->DAG Pattern Instruction Selection"; + } + + /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for + /// inline asm expressions. + virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, + char ConstraintCode, + std::vector<SDValue> &OutOps) { + SDValue Op0; + switch (ConstraintCode) { + default: return true; + case 'm': // memory + Op0 = Op; + break; + } + + OutOps.push_back(Op0); + return false; + } + +// Include the pieces autogenerated from the target description. +#include "AlphaGenDAGISel.inc" + +private: + SDValue getGlobalBaseReg(); + SDValue getGlobalRetAddr(); + void SelectCALL(SDValue Op); + + }; +} + +/// getGlobalBaseReg - Output the instructions required to put the +/// GOT address into a register. +/// +SDValue AlphaDAGToDAGISel::getGlobalBaseReg() { + unsigned GP = 0; + for(MachineRegisterInfo::livein_iterator ii = RegInfo->livein_begin(), + ee = RegInfo->livein_end(); ii != ee; ++ii) + if (ii->first == Alpha::R29) { + GP = ii->second; + break; + } + assert(GP && "GOT PTR not in liveins"); + // FIXME is there anywhere sensible to get a DebugLoc here? + return CurDAG->getCopyFromReg(CurDAG->getEntryNode(), + DebugLoc::getUnknownLoc(), GP, MVT::i64); +} + +/// getRASaveReg - Grab the return address +/// +SDValue AlphaDAGToDAGISel::getGlobalRetAddr() { + unsigned RA = 0; + for(MachineRegisterInfo::livein_iterator ii = RegInfo->livein_begin(), + ee = RegInfo->livein_end(); ii != ee; ++ii) + if (ii->first == Alpha::R26) { + RA = ii->second; + break; + } + assert(RA && "RA PTR not in liveins"); + // FIXME is there anywhere sensible to get a DebugLoc here? + return CurDAG->getCopyFromReg(CurDAG->getEntryNode(), + DebugLoc::getUnknownLoc(), RA, MVT::i64); +} + +/// InstructionSelect - This callback is invoked by +/// SelectionDAGISel when it has created a SelectionDAG for us to codegen. +void AlphaDAGToDAGISel::InstructionSelect() { + DEBUG(BB->dump()); + + // Select target instructions for the DAG. + SelectRoot(*CurDAG); + CurDAG->RemoveDeadNodes(); +} + +// Select - Convert the specified operand from a target-independent to a +// target-specific node if it hasn't already been changed. +SDNode *AlphaDAGToDAGISel::Select(SDValue Op) { + SDNode *N = Op.getNode(); + if (N->isMachineOpcode()) { + return NULL; // Already selected. + } + DebugLoc dl = N->getDebugLoc(); + + switch (N->getOpcode()) { + default: break; + case AlphaISD::CALL: + SelectCALL(Op); + return NULL; + + case ISD::FrameIndex: { + int FI = cast<FrameIndexSDNode>(N)->getIndex(); + return CurDAG->SelectNodeTo(N, Alpha::LDA, MVT::i64, + CurDAG->getTargetFrameIndex(FI, MVT::i32), + getI64Imm(0)); + } + case ISD::GLOBAL_OFFSET_TABLE: { + SDValue Result = getGlobalBaseReg(); + ReplaceUses(Op, Result); + return NULL; + } + case AlphaISD::GlobalRetAddr: { + SDValue Result = getGlobalRetAddr(); + ReplaceUses(Op, Result); + return NULL; + } + + case AlphaISD::DivCall: { + SDValue Chain = CurDAG->getEntryNode(); + SDValue N0 = Op.getOperand(0); + SDValue N1 = Op.getOperand(1); + SDValue N2 = Op.getOperand(2); + Chain = CurDAG->getCopyToReg(Chain, dl, Alpha::R24, N1, + SDValue(0,0)); + Chain = CurDAG->getCopyToReg(Chain, dl, Alpha::R25, N2, + Chain.getValue(1)); + Chain = CurDAG->getCopyToReg(Chain, dl, Alpha::R27, N0, + Chain.getValue(1)); + SDNode *CNode = + CurDAG->getTargetNode(Alpha::JSRs, dl, MVT::Other, MVT::Flag, + Chain, Chain.getValue(1)); + Chain = CurDAG->getCopyFromReg(Chain, dl, Alpha::R27, MVT::i64, + SDValue(CNode, 1)); + return CurDAG->SelectNodeTo(N, Alpha::BISr, MVT::i64, Chain, Chain); + } + + case ISD::READCYCLECOUNTER: { + SDValue Chain = N->getOperand(0); + return CurDAG->getTargetNode(Alpha::RPCC, dl, MVT::i64, MVT::Other, + Chain); + } + + case ISD::Constant: { + uint64_t uval = cast<ConstantSDNode>(N)->getZExtValue(); + + if (uval == 0) { + SDValue Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl, + Alpha::R31, MVT::i64); + ReplaceUses(Op, Result); + return NULL; + } + + int64_t val = (int64_t)uval; + int32_t val32 = (int32_t)val; + if (val <= IMM_HIGH + IMM_HIGH * IMM_MULT && + val >= IMM_LOW + IMM_LOW * IMM_MULT) + break; //(LDAH (LDA)) + if ((uval >> 32) == 0 && //empty upper bits + val32 <= IMM_HIGH + IMM_HIGH * IMM_MULT) + // val32 >= IMM_LOW + IMM_LOW * IMM_MULT) //always true + break; //(zext (LDAH (LDA))) + //Else use the constant pool + ConstantInt *C = ConstantInt::get(Type::Int64Ty, uval); + SDValue CPI = CurDAG->getTargetConstantPool(C, MVT::i64); + SDNode *Tmp = CurDAG->getTargetNode(Alpha::LDAHr, dl, MVT::i64, CPI, + getGlobalBaseReg()); + return CurDAG->SelectNodeTo(N, Alpha::LDQr, MVT::i64, MVT::Other, + CPI, SDValue(Tmp, 0), CurDAG->getEntryNode()); + } + case ISD::TargetConstantFP: + case ISD::ConstantFP: { + ConstantFPSDNode *CN = cast<ConstantFPSDNode>(N); + bool isDouble = N->getValueType(0) == MVT::f64; + MVT T = isDouble ? MVT::f64 : MVT::f32; + if (CN->getValueAPF().isPosZero()) { + return CurDAG->SelectNodeTo(N, isDouble ? Alpha::CPYST : Alpha::CPYSS, + T, CurDAG->getRegister(Alpha::F31, T), + CurDAG->getRegister(Alpha::F31, T)); + } else if (CN->getValueAPF().isNegZero()) { + return CurDAG->SelectNodeTo(N, isDouble ? Alpha::CPYSNT : Alpha::CPYSNS, + T, CurDAG->getRegister(Alpha::F31, T), + CurDAG->getRegister(Alpha::F31, T)); + } else { + abort(); + } + break; + } + + case ISD::SETCC: + if (N->getOperand(0).getNode()->getValueType(0).isFloatingPoint()) { + ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get(); + + unsigned Opc = Alpha::WTF; + bool rev = false; + bool inv = false; + switch(CC) { + default: DEBUG(N->dump(CurDAG)); assert(0 && "Unknown FP comparison!"); + case ISD::SETEQ: case ISD::SETOEQ: case ISD::SETUEQ: + Opc = Alpha::CMPTEQ; break; + case ISD::SETLT: case ISD::SETOLT: case ISD::SETULT: + Opc = Alpha::CMPTLT; break; + case ISD::SETLE: case ISD::SETOLE: case ISD::SETULE: + Opc = Alpha::CMPTLE; break; + case ISD::SETGT: case ISD::SETOGT: case ISD::SETUGT: + Opc = Alpha::CMPTLT; rev = true; break; + case ISD::SETGE: case ISD::SETOGE: case ISD::SETUGE: + Opc = Alpha::CMPTLE; rev = true; break; + case ISD::SETNE: case ISD::SETONE: case ISD::SETUNE: + Opc = Alpha::CMPTEQ; inv = true; break; + case ISD::SETO: + Opc = Alpha::CMPTUN; inv = true; break; + case ISD::SETUO: + Opc = Alpha::CMPTUN; break; + }; + SDValue tmp1 = N->getOperand(rev?1:0); + SDValue tmp2 = N->getOperand(rev?0:1); + SDNode *cmp = CurDAG->getTargetNode(Opc, dl, MVT::f64, tmp1, tmp2); + if (inv) + cmp = CurDAG->getTargetNode(Alpha::CMPTEQ, dl, + MVT::f64, SDValue(cmp, 0), + CurDAG->getRegister(Alpha::F31, MVT::f64)); + switch(CC) { + case ISD::SETUEQ: case ISD::SETULT: case ISD::SETULE: + case ISD::SETUNE: case ISD::SETUGT: case ISD::SETUGE: + { + SDNode* cmp2 = CurDAG->getTargetNode(Alpha::CMPTUN, dl, MVT::f64, + tmp1, tmp2); + cmp = CurDAG->getTargetNode(Alpha::ADDT, dl, MVT::f64, + SDValue(cmp2, 0), SDValue(cmp, 0)); + break; + } + default: break; + } + + SDNode* LD = CurDAG->getTargetNode(Alpha::FTOIT, dl, + MVT::i64, SDValue(cmp, 0)); + return CurDAG->getTargetNode(Alpha::CMPULT, dl, MVT::i64, + CurDAG->getRegister(Alpha::R31, MVT::i64), + SDValue(LD,0)); + } + break; + + case ISD::SELECT: + if (N->getValueType(0).isFloatingPoint() && + (N->getOperand(0).getOpcode() != ISD::SETCC || + !N->getOperand(0).getOperand(1).getValueType().isFloatingPoint())) { + //This should be the condition not covered by the Patterns + //FIXME: Don't have SelectCode die, but rather return something testable + // so that things like this can be caught in fall though code + //move int to fp + bool isDouble = N->getValueType(0) == MVT::f64; + SDValue cond = N->getOperand(0); + SDValue TV = N->getOperand(1); + SDValue FV = N->getOperand(2); + + SDNode* LD = CurDAG->getTargetNode(Alpha::ITOFT, dl, MVT::f64, cond); + return CurDAG->getTargetNode(isDouble?Alpha::FCMOVNET:Alpha::FCMOVNES, + dl, MVT::f64, FV, TV, SDValue(LD,0)); + } + break; + + case ISD::AND: { + ConstantSDNode* SC = NULL; + ConstantSDNode* MC = NULL; + if (N->getOperand(0).getOpcode() == ISD::SRL && + (MC = dyn_cast<ConstantSDNode>(N->getOperand(1))) && + (SC = dyn_cast<ConstantSDNode>(N->getOperand(0).getOperand(1)))) { + uint64_t sval = SC->getZExtValue(); + uint64_t mval = MC->getZExtValue(); + // If the result is a zap, let the autogened stuff handle it. + if (get_zapImm(N->getOperand(0), mval)) + break; + // given mask X, and shift S, we want to see if there is any zap in the + // mask if we play around with the botton S bits + uint64_t dontcare = (~0ULL) >> (64 - sval); + uint64_t mask = mval << sval; + + if (get_zapImm(mask | dontcare)) + mask = mask | dontcare; + + if (get_zapImm(mask)) { + SDValue Z = + SDValue(CurDAG->getTargetNode(Alpha::ZAPNOTi, dl, MVT::i64, + N->getOperand(0).getOperand(0), + getI64Imm(get_zapImm(mask))), 0); + return CurDAG->getTargetNode(Alpha::SRLr, dl, MVT::i64, Z, + getI64Imm(sval)); + } + } + break; + } + + } + + return SelectCode(Op); +} + +void AlphaDAGToDAGISel::SelectCALL(SDValue Op) { + //TODO: add flag stuff to prevent nondeturministic breakage! + + SDNode *N = Op.getNode(); + SDValue Chain = N->getOperand(0); + SDValue Addr = N->getOperand(1); + SDValue InFlag(0,0); // Null incoming flag value. + DebugLoc dl = N->getDebugLoc(); + + std::vector<SDValue> CallOperands; + std::vector<MVT> TypeOperands; + + //grab the arguments + for(int i = 2, e = N->getNumOperands(); i < e; ++i) { + TypeOperands.push_back(N->getOperand(i).getValueType()); + CallOperands.push_back(N->getOperand(i)); + } + int count = N->getNumOperands() - 2; + + static const unsigned args_int[] = {Alpha::R16, Alpha::R17, Alpha::R18, + Alpha::R19, Alpha::R20, Alpha::R21}; + static const unsigned args_float[] = {Alpha::F16, Alpha::F17, Alpha::F18, + Alpha::F19, Alpha::F20, Alpha::F21}; + + for (int i = 6; i < count; ++i) { + unsigned Opc = Alpha::WTF; + if (TypeOperands[i].isInteger()) { + Opc = Alpha::STQ; + } else if (TypeOperands[i] == MVT::f32) { + Opc = Alpha::STS; + } else if (TypeOperands[i] == MVT::f64) { + Opc = Alpha::STT; + } else + assert(0 && "Unknown operand"); + + SDValue Ops[] = { CallOperands[i], getI64Imm((i - 6) * 8), + CurDAG->getCopyFromReg(Chain, dl, Alpha::R30, MVT::i64), + Chain }; + Chain = SDValue(CurDAG->getTargetNode(Opc, dl, MVT::Other, Ops, 4), 0); + } + for (int i = 0; i < std::min(6, count); ++i) { + if (TypeOperands[i].isInteger()) { + Chain = CurDAG->getCopyToReg(Chain, dl, args_int[i], + CallOperands[i], InFlag); + InFlag = Chain.getValue(1); + } else if (TypeOperands[i] == MVT::f32 || TypeOperands[i] == MVT::f64) { + Chain = CurDAG->getCopyToReg(Chain, dl, args_float[i], + CallOperands[i], InFlag); + InFlag = Chain.getValue(1); + } else + assert(0 && "Unknown operand"); + } + + // Finally, once everything is in registers to pass to the call, emit the + // call itself. + if (Addr.getOpcode() == AlphaISD::GPRelLo) { + SDValue GOT = getGlobalBaseReg(); + Chain = CurDAG->getCopyToReg(Chain, dl, Alpha::R29, GOT, InFlag); + InFlag = Chain.getValue(1); + Chain = SDValue(CurDAG->getTargetNode(Alpha::BSR, dl, MVT::Other, + MVT::Flag, Addr.getOperand(0), + Chain, InFlag), 0); + } else { + Chain = CurDAG->getCopyToReg(Chain, dl, Alpha::R27, Addr, InFlag); + InFlag = Chain.getValue(1); + Chain = SDValue(CurDAG->getTargetNode(Alpha::JSR, dl, MVT::Other, + MVT::Flag, Chain, InFlag), 0); + } + InFlag = Chain.getValue(1); + + std::vector<SDValue> CallResults; + + switch (N->getValueType(0).getSimpleVT()) { + default: assert(0 && "Unexpected ret value!"); + case MVT::Other: break; + case MVT::i64: + Chain = CurDAG->getCopyFromReg(Chain, dl, + Alpha::R0, MVT::i64, InFlag).getValue(1); + CallResults.push_back(Chain.getValue(0)); + break; + case MVT::f32: + Chain = CurDAG->getCopyFromReg(Chain, dl, + Alpha::F0, MVT::f32, InFlag).getValue(1); + CallResults.push_back(Chain.getValue(0)); + break; + case MVT::f64: + Chain = CurDAG->getCopyFromReg(Chain, dl, + Alpha::F0, MVT::f64, InFlag).getValue(1); + CallResults.push_back(Chain.getValue(0)); + break; + } + + CallResults.push_back(Chain); + for (unsigned i = 0, e = CallResults.size(); i != e; ++i) + ReplaceUses(Op.getValue(i), CallResults[i]); +} + + +/// createAlphaISelDag - This pass converts a legalized DAG into a +/// Alpha-specific DAG, ready for instruction scheduling. +/// +FunctionPass *llvm::createAlphaISelDag(AlphaTargetMachine &TM) { + return new AlphaDAGToDAGISel(TM); +} diff --git a/lib/Target/Alpha/AlphaISelLowering.cpp b/lib/Target/Alpha/AlphaISelLowering.cpp new file mode 100644 index 000000000000..10011125cf85 --- /dev/null +++ b/lib/Target/Alpha/AlphaISelLowering.cpp @@ -0,0 +1,798 @@ +//===-- AlphaISelLowering.cpp - Alpha 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 implements the AlphaISelLowering class. +// +//===----------------------------------------------------------------------===// + +#include "AlphaISelLowering.h" +#include "AlphaTargetMachine.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Constants.h" +#include "llvm/Function.h" +#include "llvm/Module.h" +#include "llvm/Intrinsics.h" +#include "llvm/Support/CommandLine.h" +using namespace llvm; + +/// AddLiveIn - This helper function adds the specified physical register to the +/// MachineFunction as a live in value. It also creates a corresponding virtual +/// register for it. +static unsigned AddLiveIn(MachineFunction &MF, unsigned PReg, + TargetRegisterClass *RC) { + assert(RC->contains(PReg) && "Not the correct regclass!"); + unsigned VReg = MF.getRegInfo().createVirtualRegister(RC); + MF.getRegInfo().addLiveIn(PReg, VReg); + return VReg; +} + +AlphaTargetLowering::AlphaTargetLowering(TargetMachine &TM) : TargetLowering(TM) { + // Set up the TargetLowering object. + //I am having problems with shr n ubyte 1 + setShiftAmountType(MVT::i64); + setBooleanContents(ZeroOrOneBooleanContent); + + setUsesGlobalOffsetTable(true); + + addRegisterClass(MVT::i64, Alpha::GPRCRegisterClass); + addRegisterClass(MVT::f64, Alpha::F8RCRegisterClass); + addRegisterClass(MVT::f32, Alpha::F4RCRegisterClass); + + // We want to custom lower some of our intrinsics. + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); + + setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand); + + setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, Expand); + + setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, MVT::i8, Expand); + setLoadExtAction(ISD::SEXTLOAD, MVT::i16, Expand); + + // setOperationAction(ISD::BRIND, MVT::Other, Expand); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BR_CC, MVT::Other, Expand); + setOperationAction(ISD::SELECT_CC, MVT::Other, Expand); + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + + setOperationAction(ISD::FREM, MVT::f32, Expand); + setOperationAction(ISD::FREM, MVT::f64, Expand); + + setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand); + setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom); + setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand); + setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom); + + if (!TM.getSubtarget<AlphaSubtarget>().hasCT()) { + setOperationAction(ISD::CTPOP , MVT::i64 , Expand); + setOperationAction(ISD::CTTZ , MVT::i64 , Expand); + setOperationAction(ISD::CTLZ , MVT::i64 , Expand); + } + setOperationAction(ISD::BSWAP , MVT::i64, Expand); + setOperationAction(ISD::ROTL , MVT::i64, Expand); + setOperationAction(ISD::ROTR , MVT::i64, Expand); + + setOperationAction(ISD::SREM , MVT::i64, Custom); + setOperationAction(ISD::UREM , MVT::i64, Custom); + setOperationAction(ISD::SDIV , MVT::i64, Custom); + setOperationAction(ISD::UDIV , MVT::i64, Custom); + + setOperationAction(ISD::ADDC , MVT::i64, Expand); + setOperationAction(ISD::ADDE , MVT::i64, Expand); + setOperationAction(ISD::SUBC , MVT::i64, Expand); + setOperationAction(ISD::SUBE , MVT::i64, Expand); + + setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); + + + // We don't support sin/cos/sqrt/pow + setOperationAction(ISD::FSIN , MVT::f64, Expand); + setOperationAction(ISD::FCOS , MVT::f64, Expand); + setOperationAction(ISD::FSIN , MVT::f32, Expand); + setOperationAction(ISD::FCOS , MVT::f32, Expand); + + setOperationAction(ISD::FSQRT, MVT::f64, Expand); + setOperationAction(ISD::FSQRT, MVT::f32, Expand); + + setOperationAction(ISD::FPOW , MVT::f32, Expand); + setOperationAction(ISD::FPOW , MVT::f64, Expand); + + setOperationAction(ISD::SETCC, MVT::f32, Promote); + + setOperationAction(ISD::BIT_CONVERT, MVT::f32, Promote); + + // We don't have line number support yet. + setOperationAction(ISD::DBG_STOPPOINT, MVT::Other, Expand); + setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand); + setOperationAction(ISD::DBG_LABEL, MVT::Other, Expand); + setOperationAction(ISD::EH_LABEL, MVT::Other, Expand); + + // Not implemented yet. + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand); + + // We want to legalize GlobalAddress and ConstantPool and + // ExternalSymbols nodes into the appropriate instructions to + // materialize the address. + setOperationAction(ISD::GlobalAddress, MVT::i64, Custom); + setOperationAction(ISD::ConstantPool, MVT::i64, Custom); + setOperationAction(ISD::ExternalSymbol, MVT::i64, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom); + + setOperationAction(ISD::VASTART, MVT::Other, Custom); + setOperationAction(ISD::VAEND, MVT::Other, Expand); + setOperationAction(ISD::VACOPY, MVT::Other, Custom); + setOperationAction(ISD::VAARG, MVT::Other, Custom); + setOperationAction(ISD::VAARG, MVT::i32, Custom); + + setOperationAction(ISD::RET, MVT::Other, Custom); + + setOperationAction(ISD::JumpTable, MVT::i64, Custom); + setOperationAction(ISD::JumpTable, MVT::i32, Custom); + + setStackPointerRegisterToSaveRestore(Alpha::R30); + + addLegalFPImmediate(APFloat(+0.0)); //F31 + addLegalFPImmediate(APFloat(+0.0f)); //F31 + addLegalFPImmediate(APFloat(-0.0)); //-F31 + addLegalFPImmediate(APFloat(-0.0f)); //-F31 + + setJumpBufSize(272); + setJumpBufAlignment(16); + + computeRegisterProperties(); +} + +MVT AlphaTargetLowering::getSetCCResultType(MVT VT) const { + return MVT::i64; +} + +const char *AlphaTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + default: return 0; + case AlphaISD::CVTQT_: return "Alpha::CVTQT_"; + case AlphaISD::CVTQS_: return "Alpha::CVTQS_"; + case AlphaISD::CVTTQ_: return "Alpha::CVTTQ_"; + case AlphaISD::GPRelHi: return "Alpha::GPRelHi"; + case AlphaISD::GPRelLo: return "Alpha::GPRelLo"; + case AlphaISD::RelLit: return "Alpha::RelLit"; + case AlphaISD::GlobalRetAddr: return "Alpha::GlobalRetAddr"; + case AlphaISD::CALL: return "Alpha::CALL"; + case AlphaISD::DivCall: return "Alpha::DivCall"; + case AlphaISD::RET_FLAG: return "Alpha::RET_FLAG"; + case AlphaISD::COND_BRANCH_I: return "Alpha::COND_BRANCH_I"; + case AlphaISD::COND_BRANCH_F: return "Alpha::COND_BRANCH_F"; + } +} + +static SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) { + MVT PtrVT = Op.getValueType(); + JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); + SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT); + SDValue Zero = DAG.getConstant(0, PtrVT); + // FIXME there isn't really any debug info here + DebugLoc dl = Op.getDebugLoc(); + + SDValue Hi = DAG.getNode(AlphaISD::GPRelHi, dl, MVT::i64, JTI, + DAG.getGLOBAL_OFFSET_TABLE(MVT::i64)); + SDValue Lo = DAG.getNode(AlphaISD::GPRelLo, dl, MVT::i64, JTI, Hi); + return Lo; +} + +//http://www.cs.arizona.edu/computer.help/policy/DIGITAL_unix/ +//AA-PY8AC-TET1_html/callCH3.html#BLOCK21 + +//For now, just use variable size stack frame format + +//In a standard call, the first six items are passed in registers $16 +//- $21 and/or registers $f16 - $f21. (See Section 4.1.2 for details +//of argument-to-register correspondence.) The remaining items are +//collected in a memory argument list that is a naturally aligned +//array of quadwords. In a standard call, this list, if present, must +//be passed at 0(SP). +//7 ... n 0(SP) ... (n-7)*8(SP) + +// //#define FP $15 +// //#define RA $26 +// //#define PV $27 +// //#define GP $29 +// //#define SP $30 + +static SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG, + int &VarArgsBase, + int &VarArgsOffset) { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + std::vector<SDValue> ArgValues; + SDValue Root = Op.getOperand(0); + DebugLoc dl = Op.getDebugLoc(); + + AddLiveIn(MF, Alpha::R29, &Alpha::GPRCRegClass); //GP + AddLiveIn(MF, Alpha::R26, &Alpha::GPRCRegClass); //RA + + unsigned args_int[] = { + Alpha::R16, Alpha::R17, Alpha::R18, Alpha::R19, Alpha::R20, Alpha::R21}; + unsigned args_float[] = { + Alpha::F16, Alpha::F17, Alpha::F18, Alpha::F19, Alpha::F20, Alpha::F21}; + + for (unsigned ArgNo = 0, e = Op.getNode()->getNumValues()-1; ArgNo != e; ++ArgNo) { + SDValue argt; + MVT ObjectVT = Op.getValue(ArgNo).getValueType(); + SDValue ArgVal; + + if (ArgNo < 6) { + switch (ObjectVT.getSimpleVT()) { + default: + assert(false && "Invalid value type!"); + case MVT::f64: + args_float[ArgNo] = AddLiveIn(MF, args_float[ArgNo], + &Alpha::F8RCRegClass); + ArgVal = DAG.getCopyFromReg(Root, dl, args_float[ArgNo], ObjectVT); + break; + case MVT::f32: + args_float[ArgNo] = AddLiveIn(MF, args_float[ArgNo], + &Alpha::F4RCRegClass); + ArgVal = DAG.getCopyFromReg(Root, dl, args_float[ArgNo], ObjectVT); + break; + case MVT::i64: + args_int[ArgNo] = AddLiveIn(MF, args_int[ArgNo], + &Alpha::GPRCRegClass); + ArgVal = DAG.getCopyFromReg(Root, dl, args_int[ArgNo], MVT::i64); + break; + } + } else { //more args + // Create the frame index object for this incoming parameter... + int FI = MFI->CreateFixedObject(8, 8 * (ArgNo - 6)); + + // Create the SelectionDAG nodes corresponding to a load + //from this parameter + SDValue FIN = DAG.getFrameIndex(FI, MVT::i64); + ArgVal = DAG.getLoad(ObjectVT, dl, Root, FIN, NULL, 0); + } + ArgValues.push_back(ArgVal); + } + + // If the functions takes variable number of arguments, copy all regs to stack + bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue() != 0; + if (isVarArg) { + VarArgsOffset = (Op.getNode()->getNumValues()-1) * 8; + std::vector<SDValue> LS; + for (int i = 0; i < 6; ++i) { + if (TargetRegisterInfo::isPhysicalRegister(args_int[i])) + args_int[i] = AddLiveIn(MF, args_int[i], &Alpha::GPRCRegClass); + SDValue argt = DAG.getCopyFromReg(Root, dl, args_int[i], MVT::i64); + int FI = MFI->CreateFixedObject(8, -8 * (6 - i)); + if (i == 0) VarArgsBase = FI; + SDValue SDFI = DAG.getFrameIndex(FI, MVT::i64); + LS.push_back(DAG.getStore(Root, dl, argt, SDFI, NULL, 0)); + + if (TargetRegisterInfo::isPhysicalRegister(args_float[i])) + args_float[i] = AddLiveIn(MF, args_float[i], &Alpha::F8RCRegClass); + argt = DAG.getCopyFromReg(Root, dl, args_float[i], MVT::f64); + FI = MFI->CreateFixedObject(8, - 8 * (12 - i)); + SDFI = DAG.getFrameIndex(FI, MVT::i64); + LS.push_back(DAG.getStore(Root, dl, argt, SDFI, NULL, 0)); + } + + //Set up a token factor with all the stack traffic + Root = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &LS[0], LS.size()); + } + + ArgValues.push_back(Root); + + // Return the new list of results. + return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(), + &ArgValues[0], ArgValues.size()); +} + +static SDValue LowerRET(SDValue Op, SelectionDAG &DAG) { + DebugLoc dl = Op.getDebugLoc(); + SDValue Copy = DAG.getCopyToReg(Op.getOperand(0), dl, Alpha::R26, + DAG.getNode(AlphaISD::GlobalRetAddr, + DebugLoc::getUnknownLoc(), + MVT::i64), + SDValue()); + switch (Op.getNumOperands()) { + default: + assert(0 && "Do not know how to return this many arguments!"); + abort(); + case 1: + break; + //return SDValue(); // ret void is legal + case 3: { + MVT ArgVT = Op.getOperand(1).getValueType(); + unsigned ArgReg; + if (ArgVT.isInteger()) + ArgReg = Alpha::R0; + else { + assert(ArgVT.isFloatingPoint()); + ArgReg = Alpha::F0; + } + Copy = DAG.getCopyToReg(Copy, dl, ArgReg, + Op.getOperand(1), Copy.getValue(1)); + if (DAG.getMachineFunction().getRegInfo().liveout_empty()) + DAG.getMachineFunction().getRegInfo().addLiveOut(ArgReg); + break; + } + case 5: { + MVT ArgVT = Op.getOperand(1).getValueType(); + unsigned ArgReg1, ArgReg2; + if (ArgVT.isInteger()) { + ArgReg1 = Alpha::R0; + ArgReg2 = Alpha::R1; + } else { + assert(ArgVT.isFloatingPoint()); + ArgReg1 = Alpha::F0; + ArgReg2 = Alpha::F1; + } + Copy = DAG.getCopyToReg(Copy, dl, ArgReg1, + Op.getOperand(1), Copy.getValue(1)); + if (std::find(DAG.getMachineFunction().getRegInfo().liveout_begin(), + DAG.getMachineFunction().getRegInfo().liveout_end(), ArgReg1) + == DAG.getMachineFunction().getRegInfo().liveout_end()) + DAG.getMachineFunction().getRegInfo().addLiveOut(ArgReg1); + Copy = DAG.getCopyToReg(Copy, dl, ArgReg2, + Op.getOperand(3), Copy.getValue(1)); + if (std::find(DAG.getMachineFunction().getRegInfo().liveout_begin(), + DAG.getMachineFunction().getRegInfo().liveout_end(), ArgReg2) + == DAG.getMachineFunction().getRegInfo().liveout_end()) + DAG.getMachineFunction().getRegInfo().addLiveOut(ArgReg2); + break; + } + } + return DAG.getNode(AlphaISD::RET_FLAG, dl, + MVT::Other, Copy, Copy.getValue(1)); +} + +std::pair<SDValue, SDValue> +AlphaTargetLowering::LowerCallTo(SDValue Chain, const Type *RetTy, + bool RetSExt, bool RetZExt, bool isVarArg, + bool isInreg, unsigned CallingConv, + bool isTailCall, SDValue Callee, + ArgListTy &Args, SelectionDAG &DAG, + DebugLoc dl) { + int NumBytes = 0; + if (Args.size() > 6) + NumBytes = (Args.size() - 6) * 8; + + Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(NumBytes, true)); + std::vector<SDValue> args_to_use; + for (unsigned i = 0, e = Args.size(); i != e; ++i) + { + switch (getValueType(Args[i].Ty).getSimpleVT()) { + default: assert(0 && "Unexpected ValueType for argument!"); + case MVT::i1: + case MVT::i8: + case MVT::i16: + case MVT::i32: + // Promote the integer to 64 bits. If the input type is signed use a + // sign extend, otherwise use a zero extend. + if (Args[i].isSExt) + Args[i].Node = DAG.getNode(ISD::SIGN_EXTEND, dl, + MVT::i64, Args[i].Node); + else if (Args[i].isZExt) + Args[i].Node = DAG.getNode(ISD::ZERO_EXTEND, dl, + MVT::i64, Args[i].Node); + else + Args[i].Node = DAG.getNode(ISD::ANY_EXTEND, dl, MVT::i64, Args[i].Node); + break; + case MVT::i64: + case MVT::f64: + case MVT::f32: + break; + } + args_to_use.push_back(Args[i].Node); + } + + std::vector<MVT> RetVals; + MVT RetTyVT = getValueType(RetTy); + MVT ActualRetTyVT = RetTyVT; + if (RetTyVT.getSimpleVT() >= MVT::i1 && RetTyVT.getSimpleVT() <= MVT::i32) + ActualRetTyVT = MVT::i64; + + if (RetTyVT != MVT::isVoid) + RetVals.push_back(ActualRetTyVT); + RetVals.push_back(MVT::Other); + + std::vector<SDValue> Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + Ops.insert(Ops.end(), args_to_use.begin(), args_to_use.end()); + SDValue TheCall = DAG.getNode(AlphaISD::CALL, dl, + RetVals, &Ops[0], Ops.size()); + Chain = TheCall.getValue(RetTyVT != MVT::isVoid); + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, true), + DAG.getIntPtrConstant(0, true), SDValue()); + SDValue RetVal = TheCall; + + if (RetTyVT != ActualRetTyVT) { + ISD::NodeType AssertKind = ISD::DELETED_NODE; + if (RetSExt) + AssertKind = ISD::AssertSext; + else if (RetZExt) + AssertKind = ISD::AssertZext; + + if (AssertKind != ISD::DELETED_NODE) + RetVal = DAG.getNode(AssertKind, dl, MVT::i64, RetVal, + DAG.getValueType(RetTyVT)); + + RetVal = DAG.getNode(ISD::TRUNCATE, dl, RetTyVT, RetVal); + } + + return std::make_pair(RetVal, Chain); +} + +void AlphaTargetLowering::LowerVAARG(SDNode *N, SDValue &Chain, + SDValue &DataPtr, SelectionDAG &DAG) { + Chain = N->getOperand(0); + SDValue VAListP = N->getOperand(1); + const Value *VAListS = cast<SrcValueSDNode>(N->getOperand(2))->getValue(); + DebugLoc dl = N->getDebugLoc(); + + SDValue Base = DAG.getLoad(MVT::i64, dl, Chain, VAListP, VAListS, 0); + SDValue Tmp = DAG.getNode(ISD::ADD, dl, MVT::i64, VAListP, + DAG.getConstant(8, MVT::i64)); + SDValue Offset = DAG.getExtLoad(ISD::SEXTLOAD, dl, MVT::i64, Base.getValue(1), + Tmp, NULL, 0, MVT::i32); + DataPtr = DAG.getNode(ISD::ADD, dl, MVT::i64, Base, Offset); + if (N->getValueType(0).isFloatingPoint()) + { + //if fp && Offset < 6*8, then subtract 6*8 from DataPtr + SDValue FPDataPtr = DAG.getNode(ISD::SUB, dl, MVT::i64, DataPtr, + DAG.getConstant(8*6, MVT::i64)); + SDValue CC = DAG.getSetCC(dl, MVT::i64, Offset, + DAG.getConstant(8*6, MVT::i64), ISD::SETLT); + DataPtr = DAG.getNode(ISD::SELECT, dl, MVT::i64, CC, FPDataPtr, DataPtr); + } + + SDValue NewOffset = DAG.getNode(ISD::ADD, dl, MVT::i64, Offset, + DAG.getConstant(8, MVT::i64)); + Chain = DAG.getTruncStore(Offset.getValue(1), dl, NewOffset, Tmp, NULL, 0, + MVT::i32); +} + +/// LowerOperation - Provide custom lowering hooks for some operations. +/// +SDValue AlphaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { + DebugLoc dl = Op.getDebugLoc(); + switch (Op.getOpcode()) { + default: assert(0 && "Wasn't expecting to be able to lower this!"); + case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG, + VarArgsBase, + VarArgsOffset); + + case ISD::RET: return LowerRET(Op,DAG); + case ISD::JumpTable: return LowerJumpTable(Op, DAG); + + case ISD::INTRINSIC_WO_CHAIN: { + unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); + switch (IntNo) { + default: break; // Don't custom lower most intrinsics. + case Intrinsic::alpha_umulh: + return DAG.getNode(ISD::MULHU, dl, MVT::i64, + Op.getOperand(1), Op.getOperand(2)); + } + } + + case ISD::SINT_TO_FP: { + assert(Op.getOperand(0).getValueType() == MVT::i64 && + "Unhandled SINT_TO_FP type in custom expander!"); + SDValue LD; + bool isDouble = Op.getValueType() == MVT::f64; + LD = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f64, Op.getOperand(0)); + SDValue FP = DAG.getNode(isDouble?AlphaISD::CVTQT_:AlphaISD::CVTQS_, dl, + isDouble?MVT::f64:MVT::f32, LD); + return FP; + } + case ISD::FP_TO_SINT: { + bool isDouble = Op.getOperand(0).getValueType() == MVT::f64; + SDValue src = Op.getOperand(0); + + if (!isDouble) //Promote + src = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f64, src); + + src = DAG.getNode(AlphaISD::CVTTQ_, dl, MVT::f64, src); + + return DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i64, src); + } + case ISD::ConstantPool: { + ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op); + Constant *C = CP->getConstVal(); + SDValue CPI = DAG.getTargetConstantPool(C, MVT::i64, CP->getAlignment()); + // FIXME there isn't really any debug info here + + SDValue Hi = DAG.getNode(AlphaISD::GPRelHi, dl, MVT::i64, CPI, + DAG.getGLOBAL_OFFSET_TABLE(MVT::i64)); + SDValue Lo = DAG.getNode(AlphaISD::GPRelLo, dl, MVT::i64, CPI, Hi); + return Lo; + } + case ISD::GlobalTLSAddress: + assert(0 && "TLS not implemented for Alpha."); + case ISD::GlobalAddress: { + GlobalAddressSDNode *GSDN = cast<GlobalAddressSDNode>(Op); + GlobalValue *GV = GSDN->getGlobal(); + SDValue GA = DAG.getTargetGlobalAddress(GV, MVT::i64, GSDN->getOffset()); + // FIXME there isn't really any debug info here + + // if (!GV->hasWeakLinkage() && !GV->isDeclaration() && !GV->hasLinkOnceLinkage()) { + if (GV->hasLocalLinkage()) { + SDValue Hi = DAG.getNode(AlphaISD::GPRelHi, dl, MVT::i64, GA, + DAG.getGLOBAL_OFFSET_TABLE(MVT::i64)); + SDValue Lo = DAG.getNode(AlphaISD::GPRelLo, dl, MVT::i64, GA, Hi); + return Lo; + } else + return DAG.getNode(AlphaISD::RelLit, dl, MVT::i64, GA, + DAG.getGLOBAL_OFFSET_TABLE(MVT::i64)); + } + case ISD::ExternalSymbol: { + return DAG.getNode(AlphaISD::RelLit, dl, MVT::i64, + DAG.getTargetExternalSymbol(cast<ExternalSymbolSDNode>(Op) + ->getSymbol(), MVT::i64), + DAG.getGLOBAL_OFFSET_TABLE(MVT::i64)); + } + + case ISD::UREM: + case ISD::SREM: + //Expand only on constant case + if (Op.getOperand(1).getOpcode() == ISD::Constant) { + MVT VT = Op.getNode()->getValueType(0); + SDValue Tmp1 = Op.getNode()->getOpcode() == ISD::UREM ? + BuildUDIV(Op.getNode(), DAG, NULL) : + BuildSDIV(Op.getNode(), DAG, NULL); + Tmp1 = DAG.getNode(ISD::MUL, dl, VT, Tmp1, Op.getOperand(1)); + Tmp1 = DAG.getNode(ISD::SUB, dl, VT, Op.getOperand(0), Tmp1); + return Tmp1; + } + //fall through + case ISD::SDIV: + case ISD::UDIV: + if (Op.getValueType().isInteger()) { + if (Op.getOperand(1).getOpcode() == ISD::Constant) + return Op.getOpcode() == ISD::SDIV ? BuildSDIV(Op.getNode(), DAG, NULL) + : BuildUDIV(Op.getNode(), DAG, NULL); + const char* opstr = 0; + switch (Op.getOpcode()) { + case ISD::UREM: opstr = "__remqu"; break; + case ISD::SREM: opstr = "__remq"; break; + case ISD::UDIV: opstr = "__divqu"; break; + case ISD::SDIV: opstr = "__divq"; break; + } + SDValue Tmp1 = Op.getOperand(0), + Tmp2 = Op.getOperand(1), + Addr = DAG.getExternalSymbol(opstr, MVT::i64); + return DAG.getNode(AlphaISD::DivCall, dl, MVT::i64, Addr, Tmp1, Tmp2); + } + break; + + case ISD::VAARG: { + SDValue Chain, DataPtr; + LowerVAARG(Op.getNode(), Chain, DataPtr, DAG); + + SDValue Result; + if (Op.getValueType() == MVT::i32) + Result = DAG.getExtLoad(ISD::SEXTLOAD, dl, MVT::i64, Chain, DataPtr, + NULL, 0, MVT::i32); + else + Result = DAG.getLoad(Op.getValueType(), dl, Chain, DataPtr, NULL, 0); + return Result; + } + case ISD::VACOPY: { + SDValue Chain = Op.getOperand(0); + SDValue DestP = Op.getOperand(1); + SDValue SrcP = Op.getOperand(2); + const Value *DestS = cast<SrcValueSDNode>(Op.getOperand(3))->getValue(); + const Value *SrcS = cast<SrcValueSDNode>(Op.getOperand(4))->getValue(); + + SDValue Val = DAG.getLoad(getPointerTy(), dl, Chain, SrcP, SrcS, 0); + SDValue Result = DAG.getStore(Val.getValue(1), dl, Val, DestP, DestS, 0); + SDValue NP = DAG.getNode(ISD::ADD, dl, MVT::i64, SrcP, + DAG.getConstant(8, MVT::i64)); + Val = DAG.getExtLoad(ISD::SEXTLOAD, dl, MVT::i64, Result, + NP, NULL,0, MVT::i32); + SDValue NPD = DAG.getNode(ISD::ADD, dl, MVT::i64, DestP, + DAG.getConstant(8, MVT::i64)); + return DAG.getTruncStore(Val.getValue(1), dl, Val, NPD, NULL, 0, MVT::i32); + } + case ISD::VASTART: { + SDValue Chain = Op.getOperand(0); + SDValue VAListP = Op.getOperand(1); + const Value *VAListS = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); + + // vastart stores the address of the VarArgsBase and VarArgsOffset + SDValue FR = DAG.getFrameIndex(VarArgsBase, MVT::i64); + SDValue S1 = DAG.getStore(Chain, dl, FR, VAListP, VAListS, 0); + SDValue SA2 = DAG.getNode(ISD::ADD, dl, MVT::i64, VAListP, + DAG.getConstant(8, MVT::i64)); + return DAG.getTruncStore(S1, dl, DAG.getConstant(VarArgsOffset, MVT::i64), + SA2, NULL, 0, MVT::i32); + } + case ISD::RETURNADDR: + return DAG.getNode(AlphaISD::GlobalRetAddr, DebugLoc::getUnknownLoc(), + MVT::i64); + //FIXME: implement + case ISD::FRAMEADDR: break; + } + + return SDValue(); +} + +void AlphaTargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue>&Results, + SelectionDAG &DAG) { + DebugLoc dl = N->getDebugLoc(); + assert(N->getValueType(0) == MVT::i32 && + N->getOpcode() == ISD::VAARG && + "Unknown node to custom promote!"); + + SDValue Chain, DataPtr; + LowerVAARG(N, Chain, DataPtr, DAG); + SDValue Res = DAG.getLoad(N->getValueType(0), dl, Chain, DataPtr, NULL, 0); + Results.push_back(Res); + Results.push_back(SDValue(Res.getNode(), 1)); +} + + +//Inline Asm + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +AlphaTargetLowering::ConstraintType +AlphaTargetLowering::getConstraintType(const std::string &Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default: break; + case 'f': + case 'r': + return C_RegisterClass; + } + } + return TargetLowering::getConstraintType(Constraint); +} + +std::vector<unsigned> AlphaTargetLowering:: +getRegClassForInlineAsmConstraint(const std::string &Constraint, + MVT VT) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default: break; // Unknown constriant letter + case 'f': + return make_vector<unsigned>(Alpha::F0 , Alpha::F1 , Alpha::F2 , + Alpha::F3 , Alpha::F4 , Alpha::F5 , + Alpha::F6 , Alpha::F7 , Alpha::F8 , + Alpha::F9 , Alpha::F10, Alpha::F11, + Alpha::F12, Alpha::F13, Alpha::F14, + Alpha::F15, Alpha::F16, Alpha::F17, + Alpha::F18, Alpha::F19, Alpha::F20, + Alpha::F21, Alpha::F22, Alpha::F23, + Alpha::F24, Alpha::F25, Alpha::F26, + Alpha::F27, Alpha::F28, Alpha::F29, + Alpha::F30, Alpha::F31, 0); + case 'r': + return make_vector<unsigned>(Alpha::R0 , Alpha::R1 , Alpha::R2 , + Alpha::R3 , Alpha::R4 , Alpha::R5 , + Alpha::R6 , Alpha::R7 , Alpha::R8 , + Alpha::R9 , Alpha::R10, Alpha::R11, + Alpha::R12, Alpha::R13, Alpha::R14, + Alpha::R15, Alpha::R16, Alpha::R17, + Alpha::R18, Alpha::R19, Alpha::R20, + Alpha::R21, Alpha::R22, Alpha::R23, + Alpha::R24, Alpha::R25, Alpha::R26, + Alpha::R27, Alpha::R28, Alpha::R29, + Alpha::R30, Alpha::R31, 0); + } + } + + return std::vector<unsigned>(); +} +//===----------------------------------------------------------------------===// +// Other Lowering Code +//===----------------------------------------------------------------------===// + +MachineBasicBlock * +AlphaTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + assert((MI->getOpcode() == Alpha::CAS32 || + MI->getOpcode() == Alpha::CAS64 || + MI->getOpcode() == Alpha::LAS32 || + MI->getOpcode() == Alpha::LAS64 || + MI->getOpcode() == Alpha::SWAP32 || + MI->getOpcode() == Alpha::SWAP64) && + "Unexpected instr type to insert"); + + bool is32 = MI->getOpcode() == Alpha::CAS32 || + MI->getOpcode() == Alpha::LAS32 || + MI->getOpcode() == Alpha::SWAP32; + + //Load locked store conditional for atomic ops take on the same form + //start: + //ll + //do stuff (maybe branch to exit) + //sc + //test sc and maybe branck to start + //exit: + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + DebugLoc dl = MI->getDebugLoc(); + MachineFunction::iterator It = BB; + ++It; + + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *llscMBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + + sinkMBB->transferSuccessors(thisMBB); + + F->insert(It, llscMBB); + F->insert(It, sinkMBB); + + BuildMI(thisMBB, dl, TII->get(Alpha::BR)).addMBB(llscMBB); + + unsigned reg_res = MI->getOperand(0).getReg(), + reg_ptr = MI->getOperand(1).getReg(), + reg_v2 = MI->getOperand(2).getReg(), + reg_store = F->getRegInfo().createVirtualRegister(&Alpha::GPRCRegClass); + + BuildMI(llscMBB, dl, TII->get(is32 ? Alpha::LDL_L : Alpha::LDQ_L), + reg_res).addImm(0).addReg(reg_ptr); + switch (MI->getOpcode()) { + case Alpha::CAS32: + case Alpha::CAS64: { + unsigned reg_cmp + = F->getRegInfo().createVirtualRegister(&Alpha::GPRCRegClass); + BuildMI(llscMBB, dl, TII->get(Alpha::CMPEQ), reg_cmp) + .addReg(reg_v2).addReg(reg_res); + BuildMI(llscMBB, dl, TII->get(Alpha::BEQ)) + .addImm(0).addReg(reg_cmp).addMBB(sinkMBB); + BuildMI(llscMBB, dl, TII->get(Alpha::BISr), reg_store) + .addReg(Alpha::R31).addReg(MI->getOperand(3).getReg()); + break; + } + case Alpha::LAS32: + case Alpha::LAS64: { + BuildMI(llscMBB, dl,TII->get(is32 ? Alpha::ADDLr : Alpha::ADDQr), reg_store) + .addReg(reg_res).addReg(reg_v2); + break; + } + case Alpha::SWAP32: + case Alpha::SWAP64: { + BuildMI(llscMBB, dl, TII->get(Alpha::BISr), reg_store) + .addReg(reg_v2).addReg(reg_v2); + break; + } + } + BuildMI(llscMBB, dl, TII->get(is32 ? Alpha::STL_C : Alpha::STQ_C), reg_store) + .addReg(reg_store).addImm(0).addReg(reg_ptr); + BuildMI(llscMBB, dl, TII->get(Alpha::BEQ)) + .addImm(0).addReg(reg_store).addMBB(llscMBB); + BuildMI(llscMBB, dl, TII->get(Alpha::BR)).addMBB(sinkMBB); + + thisMBB->addSuccessor(llscMBB); + llscMBB->addSuccessor(llscMBB); + llscMBB->addSuccessor(sinkMBB); + F->DeleteMachineInstr(MI); // The pseudo instruction is gone now. + + return sinkMBB; +} + +bool +AlphaTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The Alpha target isn't yet aware of offsets. + return false; +} diff --git a/lib/Target/Alpha/AlphaISelLowering.h b/lib/Target/Alpha/AlphaISelLowering.h new file mode 100644 index 000000000000..fdd817c76488 --- /dev/null +++ b/lib/Target/Alpha/AlphaISelLowering.h @@ -0,0 +1,114 @@ +//===-- AlphaISelLowering.h - Alpha 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 Alpha uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_ALPHA_ALPHAISELLOWERING_H +#define LLVM_TARGET_ALPHA_ALPHAISELLOWERING_H + +#include "llvm/ADT/VectorExtras.h" +#include "llvm/Target/TargetLowering.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "Alpha.h" + +namespace llvm { + + namespace AlphaISD { + enum NodeType { + // Start the numbering where the builting ops and target ops leave off. + FIRST_NUMBER = ISD::BUILTIN_OP_END, + //These corrospond to the identical Instruction + CVTQT_, CVTQS_, CVTTQ_, + + /// GPRelHi/GPRelLo - These represent the high and low 16-bit + /// parts of a global address respectively. + GPRelHi, GPRelLo, + + /// RetLit - Literal Relocation of a Global + RelLit, + + /// GlobalRetAddr - used to restore the return address + GlobalRetAddr, + + /// CALL - Normal call. + CALL, + + /// DIVCALL - used for special library calls for div and rem + DivCall, + + /// return flag operand + RET_FLAG, + + /// CHAIN = COND_BRANCH CHAIN, OPC, (G|F)PRC, DESTBB [, INFLAG] - This + /// corresponds to the COND_BRANCH pseudo instruction. + /// *PRC is the input register to compare to zero, + /// OPC is the branch opcode to use (e.g. Alpha::BEQ), + /// DESTBB is the destination block to branch to, and INFLAG is + /// an optional input flag argument. + COND_BRANCH_I, COND_BRANCH_F + + }; + } + + class AlphaTargetLowering : public TargetLowering { + int VarArgsOffset; // What is the offset to the first vaarg + int VarArgsBase; // What is the base FrameIndex + bool useITOF; + public: + explicit AlphaTargetLowering(TargetMachine &TM); + + /// getSetCCResultType - Get the SETCC result ValueType + virtual MVT getSetCCResultType(MVT VT) const; + + /// LowerOperation - Provide custom lowering hooks for some operations. + /// + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG); + + /// ReplaceNodeResults - Replace the results of node with an illegal result + /// type with new values built out of custom code. + /// + virtual void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue>&Results, + SelectionDAG &DAG); + + // Friendly names for dumps + const char *getTargetNodeName(unsigned Opcode) const; + + /// LowerCallTo - This hook lowers an abstract call to a function into an + /// actual call. + virtual std::pair<SDValue, SDValue> + LowerCallTo(SDValue Chain, const Type *RetTy, bool RetSExt, bool RetZExt, + bool isVarArg, bool isInreg, unsigned CC, bool isTailCall, + SDValue Callee, ArgListTy &Args, SelectionDAG &DAG, + DebugLoc dl); + + ConstraintType getConstraintType(const std::string &Constraint) const; + + std::vector<unsigned> + getRegClassForInlineAsmConstraint(const std::string &Constraint, + MVT VT) const; + + bool hasITOF() { return useITOF; } + + MachineBasicBlock *EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const; + + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + + private: + // Helpers for custom lowering. + void LowerVAARG(SDNode *N, SDValue &Chain, SDValue &DataPtr, + SelectionDAG &DAG); + + }; +} + +#endif // LLVM_TARGET_ALPHA_ALPHAISELLOWERING_H diff --git a/lib/Target/Alpha/AlphaInstrFormats.td b/lib/Target/Alpha/AlphaInstrFormats.td new file mode 100644 index 000000000000..6d82875fad2d --- /dev/null +++ b/lib/Target/Alpha/AlphaInstrFormats.td @@ -0,0 +1,268 @@ +//===- AlphaInstrFormats.td - Alpha Instruction Formats ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +//3.3: +//Memory +//Branch +//Operate +//Floating-point +//PALcode + +def u8imm : Operand<i64>; +def s14imm : Operand<i64>; +def s16imm : Operand<i64>; +def s21imm : Operand<i64>; +def s64imm : Operand<i64>; +def u64imm : Operand<i64>; + +//===----------------------------------------------------------------------===// +// Instruction format superclass +//===----------------------------------------------------------------------===// +// Alpha instruction baseline +class InstAlpha<bits<6> op, string asmstr, InstrItinClass itin> : Instruction { + field bits<32> Inst; + let Namespace = "Alpha"; + let AsmString = asmstr; + let Inst{31-26} = op; + let Itinerary = itin; +} + + +//3.3.1 +class MForm<bits<6> opcode, bit load, string asmstr, list<dag> pattern, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let Pattern = pattern; + let canFoldAsLoad = load; + let Defs = [R28]; //We may use this for frame index calculations, so reserve it here + + bits<5> Ra; + bits<16> disp; + bits<5> Rb; + + let Inst{25-21} = Ra; + let Inst{20-16} = Rb; + let Inst{15-0} = disp; +} +class MfcForm<bits<6> opcode, bits<16> fc, string asmstr, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + bits<5> Ra; + + let OutOperandList = (ops GPRC:$RA); + let InOperandList = (ops); + let Inst{25-21} = Ra; + let Inst{20-16} = 0; + let Inst{15-0} = fc; +} +class MfcPForm<bits<6> opcode, bits<16> fc, string asmstr, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let OutOperandList = (ops); + let InOperandList = (ops); + let Inst{25-21} = 0; + let Inst{20-16} = 0; + let Inst{15-0} = fc; +} + +class MbrForm<bits<6> opcode, bits<2> TB, dag OL, string asmstr, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + bits<5> Ra; + bits<5> Rb; + bits<14> disp; + + let OutOperandList = (ops); + let InOperandList = OL; + + let Inst{25-21} = Ra; + let Inst{20-16} = Rb; + let Inst{15-14} = TB; + let Inst{13-0} = disp; +} +class MbrpForm<bits<6> opcode, bits<2> TB, dag OL, string asmstr, list<dag> pattern, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let Pattern=pattern; + bits<5> Ra; + bits<5> Rb; + bits<14> disp; + + let OutOperandList = (ops); + let InOperandList = OL; + + let Inst{25-21} = Ra; + let Inst{20-16} = Rb; + let Inst{15-14} = TB; + let Inst{13-0} = disp; +} + +//3.3.2 +def target : Operand<OtherVT> {} + +let isBranch = 1, isTerminator = 1, hasCtrlDep = 1 in { +class BFormN<bits<6> opcode, dag OL, string asmstr, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let OutOperandList = (ops); + let InOperandList = OL; + bits<64> Opc; //dummy + bits<5> Ra; + bits<21> disp; + + let Inst{25-21} = Ra; + let Inst{20-0} = disp; +} +} + +let isBranch = 1, isTerminator = 1 in +class BFormD<bits<6> opcode, string asmstr, list<dag> pattern, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let Pattern = pattern; + let OutOperandList = (ops); + let InOperandList = (ops target:$DISP); + bits<5> Ra; + bits<21> disp; + + let Inst{25-21} = Ra; + let Inst{20-0} = disp; +} + +//3.3.3 +class OForm<bits<6> opcode, bits<7> fun, string asmstr, list<dag> pattern, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let Pattern = pattern; + let OutOperandList = (outs GPRC:$RC); + let InOperandList = (ins GPRC:$RA, GPRC:$RB); + + bits<5> Rc; + bits<5> Ra; + bits<5> Rb; + bits<7> Function = fun; + + let Inst{25-21} = Ra; + let Inst{20-16} = Rb; + let Inst{15-13} = 0; + let Inst{12} = 0; + let Inst{11-5} = Function; + let Inst{4-0} = Rc; +} + +class OForm2<bits<6> opcode, bits<7> fun, string asmstr, list<dag> pattern, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let Pattern = pattern; + let OutOperandList = (outs GPRC:$RC); + let InOperandList = (ins GPRC:$RB); + + bits<5> Rc; + bits<5> Rb; + bits<7> Function = fun; + + let Inst{25-21} = 31; + let Inst{20-16} = Rb; + let Inst{15-13} = 0; + let Inst{12} = 0; + let Inst{11-5} = Function; + let Inst{4-0} = Rc; +} + +class OForm4<bits<6> opcode, bits<7> fun, string asmstr, list<dag> pattern, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let Pattern = pattern; + let OutOperandList = (outs GPRC:$RDEST); + let InOperandList = (ins GPRC:$RCOND, GPRC:$RTRUE, GPRC:$RFALSE); + let Constraints = "$RFALSE = $RDEST"; + let DisableEncoding = "$RFALSE"; + + bits<5> Rc; + bits<5> Ra; + bits<5> Rb; + bits<7> Function = fun; + +// let isTwoAddress = 1; + let Inst{25-21} = Ra; + let Inst{20-16} = Rb; + let Inst{15-13} = 0; + let Inst{12} = 0; + let Inst{11-5} = Function; + let Inst{4-0} = Rc; +} + + +class OFormL<bits<6> opcode, bits<7> fun, string asmstr, list<dag> pattern, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let Pattern = pattern; + let OutOperandList = (outs GPRC:$RC); + let InOperandList = (ins GPRC:$RA, u8imm:$L); + + bits<5> Rc; + bits<5> Ra; + bits<8> LIT; + bits<7> Function = fun; + + let Inst{25-21} = Ra; + let Inst{20-13} = LIT; + let Inst{12} = 1; + let Inst{11-5} = Function; + let Inst{4-0} = Rc; +} + +class OForm4L<bits<6> opcode, bits<7> fun, string asmstr, list<dag> pattern, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let Pattern = pattern; + let OutOperandList = (outs GPRC:$RDEST); + let InOperandList = (ins GPRC:$RCOND, s64imm:$RTRUE, GPRC:$RFALSE); + let Constraints = "$RFALSE = $RDEST"; + let DisableEncoding = "$RFALSE"; + + bits<5> Rc; + bits<5> Ra; + bits<8> LIT; + bits<7> Function = fun; + +// let isTwoAddress = 1; + let Inst{25-21} = Ra; + let Inst{20-13} = LIT; + let Inst{12} = 1; + let Inst{11-5} = Function; + let Inst{4-0} = Rc; +} + +//3.3.4 +class FPForm<bits<6> opcode, bits<11> fun, string asmstr, list<dag> pattern, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let Pattern = pattern; + + bits<5> Fc; + bits<5> Fa; + bits<5> Fb; + bits<11> Function = fun; + + let Inst{25-21} = Fa; + let Inst{20-16} = Fb; + let Inst{15-5} = Function; + let Inst{4-0} = Fc; +} + +//3.3.5 +class PALForm<bits<6> opcode, dag OL, string asmstr, InstrItinClass itin> + : InstAlpha<opcode, asmstr, itin> { + let OutOperandList = (ops); + let InOperandList = OL; + bits<26> Function; + + let Inst{25-0} = Function; +} + + +// Pseudo instructions. +class PseudoInstAlpha<dag OOL, dag IOL, string nm, list<dag> pattern, InstrItinClass itin> + : InstAlpha<0, nm, itin> { + let OutOperandList = OOL; + let InOperandList = IOL; + let Pattern = pattern; + +} diff --git a/lib/Target/Alpha/AlphaInstrInfo.cpp b/lib/Target/Alpha/AlphaInstrInfo.cpp new file mode 100644 index 000000000000..a54d97d33c40 --- /dev/null +++ b/lib/Target/Alpha/AlphaInstrInfo.cpp @@ -0,0 +1,450 @@ +//===- AlphaInstrInfo.cpp - Alpha 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 Alpha implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "Alpha.h" +#include "AlphaInstrInfo.h" +#include "AlphaGenInstrInfo.inc" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +using namespace llvm; + +AlphaInstrInfo::AlphaInstrInfo() + : TargetInstrInfoImpl(AlphaInsts, array_lengthof(AlphaInsts)), + RI(*this) { } + + +bool AlphaInstrInfo::isMoveInstr(const MachineInstr& MI, + unsigned& sourceReg, unsigned& destReg, + unsigned& SrcSR, unsigned& DstSR) const { + unsigned oc = MI.getOpcode(); + if (oc == Alpha::BISr || + oc == Alpha::CPYSS || + oc == Alpha::CPYST || + oc == Alpha::CPYSSt || + oc == Alpha::CPYSTs) { + // or r1, r2, r2 + // cpys(s|t) r1 r2 r2 + assert(MI.getNumOperands() >= 3 && + MI.getOperand(0).isReg() && + MI.getOperand(1).isReg() && + MI.getOperand(2).isReg() && + "invalid Alpha BIS instruction!"); + if (MI.getOperand(1).getReg() == MI.getOperand(2).getReg()) { + sourceReg = MI.getOperand(1).getReg(); + destReg = MI.getOperand(0).getReg(); + SrcSR = DstSR = 0; + return true; + } + } + return false; +} + +unsigned +AlphaInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + switch (MI->getOpcode()) { + case Alpha::LDL: + case Alpha::LDQ: + case Alpha::LDBU: + case Alpha::LDWU: + case Alpha::LDS: + case Alpha::LDT: + if (MI->getOperand(1).isFI()) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + break; + } + return 0; +} + +unsigned +AlphaInstrInfo::isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + switch (MI->getOpcode()) { + case Alpha::STL: + case Alpha::STQ: + case Alpha::STB: + case Alpha::STW: + case Alpha::STS: + case Alpha::STT: + if (MI->getOperand(1).isFI()) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + break; + } + return 0; +} + +static bool isAlphaIntCondCode(unsigned Opcode) { + switch (Opcode) { + case Alpha::BEQ: + case Alpha::BNE: + case Alpha::BGE: + case Alpha::BGT: + case Alpha::BLE: + case Alpha::BLT: + case Alpha::BLBC: + case Alpha::BLBS: + return true; + default: + return false; + } +} + +unsigned AlphaInstrInfo::InsertBranch(MachineBasicBlock &MBB, + MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const { + // FIXME this should probably have a DebugLoc argument + DebugLoc dl = DebugLoc::getUnknownLoc(); + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + assert((Cond.size() == 2 || Cond.size() == 0) && + "Alpha branch conditions have two components!"); + + // One-way branch. + if (FBB == 0) { + if (Cond.empty()) // Unconditional branch + BuildMI(&MBB, dl, get(Alpha::BR)).addMBB(TBB); + else // Conditional branch + if (isAlphaIntCondCode(Cond[0].getImm())) + BuildMI(&MBB, dl, get(Alpha::COND_BRANCH_I)) + .addImm(Cond[0].getImm()).addReg(Cond[1].getReg()).addMBB(TBB); + else + BuildMI(&MBB, dl, get(Alpha::COND_BRANCH_F)) + .addImm(Cond[0].getImm()).addReg(Cond[1].getReg()).addMBB(TBB); + return 1; + } + + // Two-way Conditional Branch. + if (isAlphaIntCondCode(Cond[0].getImm())) + BuildMI(&MBB, dl, get(Alpha::COND_BRANCH_I)) + .addImm(Cond[0].getImm()).addReg(Cond[1].getReg()).addMBB(TBB); + else + BuildMI(&MBB, dl, get(Alpha::COND_BRANCH_F)) + .addImm(Cond[0].getImm()).addReg(Cond[1].getReg()).addMBB(TBB); + BuildMI(&MBB, dl, get(Alpha::BR)).addMBB(FBB); + return 2; +} + +bool AlphaInstrInfo::copyRegToReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const { + //cerr << "copyRegToReg " << DestReg << " <- " << SrcReg << "\n"; + if (DestRC != SrcRC) { + // Not yet supported! + return false; + } + + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + if (DestRC == Alpha::GPRCRegisterClass) { + BuildMI(MBB, MI, DL, get(Alpha::BISr), DestReg) + .addReg(SrcReg) + .addReg(SrcReg); + } else if (DestRC == Alpha::F4RCRegisterClass) { + BuildMI(MBB, MI, DL, get(Alpha::CPYSS), DestReg) + .addReg(SrcReg) + .addReg(SrcReg); + } else if (DestRC == Alpha::F8RCRegisterClass) { + BuildMI(MBB, MI, DL, get(Alpha::CPYST), DestReg) + .addReg(SrcReg) + .addReg(SrcReg); + } else { + // Attempt to copy register that is not GPR or FPR + return false; + } + + return true; +} + +void +AlphaInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FrameIdx, + const TargetRegisterClass *RC) const { + //cerr << "Trying to store " << getPrettyName(SrcReg) << " to " + // << FrameIdx << "\n"; + //BuildMI(MBB, MI, Alpha::WTF, 0).addReg(SrcReg); + + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + if (RC == Alpha::F4RCRegisterClass) + BuildMI(MBB, MI, DL, get(Alpha::STS)) + .addReg(SrcReg, getKillRegState(isKill)) + .addFrameIndex(FrameIdx).addReg(Alpha::F31); + else if (RC == Alpha::F8RCRegisterClass) + BuildMI(MBB, MI, DL, get(Alpha::STT)) + .addReg(SrcReg, getKillRegState(isKill)) + .addFrameIndex(FrameIdx).addReg(Alpha::F31); + else if (RC == Alpha::GPRCRegisterClass) + BuildMI(MBB, MI, DL, get(Alpha::STQ)) + .addReg(SrcReg, getKillRegState(isKill)) + .addFrameIndex(FrameIdx).addReg(Alpha::F31); + else + abort(); +} + +void AlphaInstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg, + bool isKill, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const { + unsigned Opc = 0; + if (RC == Alpha::F4RCRegisterClass) + Opc = Alpha::STS; + else if (RC == Alpha::F8RCRegisterClass) + Opc = Alpha::STT; + else if (RC == Alpha::GPRCRegisterClass) + Opc = Alpha::STQ; + else + abort(); + DebugLoc DL = DebugLoc::getUnknownLoc(); + MachineInstrBuilder MIB = + BuildMI(MF, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill)); + for (unsigned i = 0, e = Addr.size(); i != e; ++i) + MIB.addOperand(Addr[i]); + NewMIs.push_back(MIB); +} + +void +AlphaInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC) const { + //cerr << "Trying to load " << getPrettyName(DestReg) << " to " + // << FrameIdx << "\n"; + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + if (RC == Alpha::F4RCRegisterClass) + BuildMI(MBB, MI, DL, get(Alpha::LDS), DestReg) + .addFrameIndex(FrameIdx).addReg(Alpha::F31); + else if (RC == Alpha::F8RCRegisterClass) + BuildMI(MBB, MI, DL, get(Alpha::LDT), DestReg) + .addFrameIndex(FrameIdx).addReg(Alpha::F31); + else if (RC == Alpha::GPRCRegisterClass) + BuildMI(MBB, MI, DL, get(Alpha::LDQ), DestReg) + .addFrameIndex(FrameIdx).addReg(Alpha::F31); + else + abort(); +} + +void AlphaInstrInfo::loadRegFromAddr(MachineFunction &MF, unsigned DestReg, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const { + unsigned Opc = 0; + if (RC == Alpha::F4RCRegisterClass) + Opc = Alpha::LDS; + else if (RC == Alpha::F8RCRegisterClass) + Opc = Alpha::LDT; + else if (RC == Alpha::GPRCRegisterClass) + Opc = Alpha::LDQ; + else + abort(); + DebugLoc DL = DebugLoc::getUnknownLoc(); + MachineInstrBuilder MIB = + BuildMI(MF, DL, get(Opc), DestReg); + for (unsigned i = 0, e = Addr.size(); i != e; ++i) + MIB.addOperand(Addr[i]); + NewMIs.push_back(MIB); +} + +MachineInstr *AlphaInstrInfo::foldMemoryOperandImpl(MachineFunction &MF, + MachineInstr *MI, + const SmallVectorImpl<unsigned> &Ops, + int FrameIndex) const { + if (Ops.size() != 1) return NULL; + + // Make sure this is a reg-reg copy. + unsigned Opc = MI->getOpcode(); + + MachineInstr *NewMI = NULL; + switch(Opc) { + default: + break; + case Alpha::BISr: + case Alpha::CPYSS: + case Alpha::CPYST: + if (MI->getOperand(1).getReg() == MI->getOperand(2).getReg()) { + if (Ops[0] == 0) { // move -> store + unsigned InReg = MI->getOperand(1).getReg(); + bool isKill = MI->getOperand(1).isKill(); + Opc = (Opc == Alpha::BISr) ? Alpha::STQ : + ((Opc == Alpha::CPYSS) ? Alpha::STS : Alpha::STT); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(Opc)) + .addReg(InReg, getKillRegState(isKill)) + .addFrameIndex(FrameIndex) + .addReg(Alpha::F31); + } else { // load -> move + unsigned OutReg = MI->getOperand(0).getReg(); + bool isDead = MI->getOperand(0).isDead(); + Opc = (Opc == Alpha::BISr) ? Alpha::LDQ : + ((Opc == Alpha::CPYSS) ? Alpha::LDS : Alpha::LDT); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(Opc)) + .addReg(OutReg, RegState::Define | getDeadRegState(isDead)) + .addFrameIndex(FrameIndex) + .addReg(Alpha::F31); + } + } + break; + } + return NewMI; +} + +static unsigned AlphaRevCondCode(unsigned Opcode) { + switch (Opcode) { + case Alpha::BEQ: return Alpha::BNE; + case Alpha::BNE: return Alpha::BEQ; + case Alpha::BGE: return Alpha::BLT; + case Alpha::BGT: return Alpha::BLE; + case Alpha::BLE: return Alpha::BGT; + case Alpha::BLT: return Alpha::BGE; + case Alpha::BLBC: return Alpha::BLBS; + case Alpha::BLBS: return Alpha::BLBC; + case Alpha::FBEQ: return Alpha::FBNE; + case Alpha::FBNE: return Alpha::FBEQ; + case Alpha::FBGE: return Alpha::FBLT; + case Alpha::FBGT: return Alpha::FBLE; + case Alpha::FBLE: return Alpha::FBGT; + case Alpha::FBLT: return Alpha::FBGE; + default: + assert(0 && "Unknown opcode"); + } + return 0; // Not reached +} + +// Branch analysis. +bool AlphaInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &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() || !isUnpredicatedTerminator(--I)) + return false; + + // Get the last instruction in the block. + MachineInstr *LastInst = I; + + // If there is only one terminator instruction, process it. + if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) { + if (LastInst->getOpcode() == Alpha::BR) { + TBB = LastInst->getOperand(0).getMBB(); + return false; + } else if (LastInst->getOpcode() == Alpha::COND_BRANCH_I || + LastInst->getOpcode() == Alpha::COND_BRANCH_F) { + // Block ends with fall-through condbranch. + TBB = LastInst->getOperand(2).getMBB(); + Cond.push_back(LastInst->getOperand(0)); + Cond.push_back(LastInst->getOperand(1)); + return false; + } + // Otherwise, don't know what this is. + return true; + } + + // Get the instruction before it if it's a terminator. + MachineInstr *SecondLastInst = I; + + // 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 Alpha::BR and Alpha::COND_BRANCH_*, handle it. + if ((SecondLastInst->getOpcode() == Alpha::COND_BRANCH_I || + SecondLastInst->getOpcode() == Alpha::COND_BRANCH_F) && + LastInst->getOpcode() == Alpha::BR) { + TBB = SecondLastInst->getOperand(2).getMBB(); + Cond.push_back(SecondLastInst->getOperand(0)); + Cond.push_back(SecondLastInst->getOperand(1)); + FBB = LastInst->getOperand(0).getMBB(); + return false; + } + + // If the block ends with two Alpha::BRs, handle it. The second one is not + // executed, so remove it. + if (SecondLastInst->getOpcode() == Alpha::BR && + LastInst->getOpcode() == Alpha::BR) { + TBB = SecondLastInst->getOperand(0).getMBB(); + I = LastInst; + if (AllowModify) + I->eraseFromParent(); + return false; + } + + // Otherwise, can't handle this. + return true; +} + +unsigned AlphaInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator I = MBB.end(); + if (I == MBB.begin()) return 0; + --I; + if (I->getOpcode() != Alpha::BR && + I->getOpcode() != Alpha::COND_BRANCH_I && + I->getOpcode() != Alpha::COND_BRANCH_F) + return 0; + + // Remove the branch. + I->eraseFromParent(); + + I = MBB.end(); + + if (I == MBB.begin()) return 1; + --I; + if (I->getOpcode() != Alpha::COND_BRANCH_I && + I->getOpcode() != Alpha::COND_BRANCH_F) + return 1; + + // Remove the branch. + I->eraseFromParent(); + return 2; +} + +void AlphaInstrInfo::insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const { + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + BuildMI(MBB, MI, DL, get(Alpha::BISr), Alpha::R31) + .addReg(Alpha::R31) + .addReg(Alpha::R31); +} + +bool AlphaInstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const { + if (MBB.empty()) return false; + + switch (MBB.back().getOpcode()) { + case Alpha::RETDAG: // Return. + case Alpha::RETDAGp: + case Alpha::BR: // Uncond branch. + case Alpha::JMP: // Indirect branch. + return true; + default: return false; + } +} +bool AlphaInstrInfo:: +ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { + assert(Cond.size() == 2 && "Invalid Alpha branch opcode!"); + Cond[0].setImm(AlphaRevCondCode(Cond[0].getImm())); + return false; +} + diff --git a/lib/Target/Alpha/AlphaInstrInfo.h b/lib/Target/Alpha/AlphaInstrInfo.h new file mode 100644 index 000000000000..182aa32f447a --- /dev/null +++ b/lib/Target/Alpha/AlphaInstrInfo.h @@ -0,0 +1,97 @@ +//===- AlphaInstrInfo.h - Alpha 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 Alpha implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef ALPHAINSTRUCTIONINFO_H +#define ALPHAINSTRUCTIONINFO_H + +#include "llvm/Target/TargetInstrInfo.h" +#include "AlphaRegisterInfo.h" + +namespace llvm { + +class AlphaInstrInfo : public TargetInstrInfoImpl { + const AlphaRegisterInfo RI; +public: + AlphaInstrInfo(); + + /// 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). + /// + virtual const AlphaRegisterInfo &getRegisterInfo() const { return RI; } + + /// Return true if the instruction is a register to register move and return + /// the source and dest operands and their sub-register indices by reference. + virtual bool isMoveInstr(const MachineInstr &MI, + unsigned &SrcReg, unsigned &DstReg, + unsigned &SrcSubIdx, unsigned &DstSubIdx) const; + + virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const; + virtual unsigned isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const; + + virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const; + virtual bool copyRegToReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const; + virtual void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC) const; + + virtual void storeRegToAddr(MachineFunction &MF, unsigned SrcReg, bool isKill, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const; + + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC) const; + + virtual void loadRegFromAddr(MachineFunction &MF, unsigned DestReg, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const; + + virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF, + MachineInstr* MI, + const SmallVectorImpl<unsigned> &Ops, + int FrameIndex) const; + + virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF, + MachineInstr* MI, + const SmallVectorImpl<unsigned> &Ops, + MachineInstr* LoadMI) const { + return 0; + } + + bool AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const; + unsigned RemoveBranch(MachineBasicBlock &MBB) const; + void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const; + bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const; + bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const; +}; + +} + +#endif diff --git a/lib/Target/Alpha/AlphaInstrInfo.td b/lib/Target/Alpha/AlphaInstrInfo.td new file mode 100644 index 000000000000..e73bdf9f6e91 --- /dev/null +++ b/lib/Target/Alpha/AlphaInstrInfo.td @@ -0,0 +1,1137 @@ +//===- AlphaInstrInfo.td - The Alpha Instruction Set -------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +include "AlphaInstrFormats.td" + +//******************** +//Custom DAG Nodes +//******************** + +def SDTFPUnaryOpUnC : SDTypeProfile<1, 1, [ + SDTCisFP<1>, SDTCisFP<0> +]>; +def Alpha_cvtqt : SDNode<"AlphaISD::CVTQT_", SDTFPUnaryOpUnC, []>; +def Alpha_cvtqs : SDNode<"AlphaISD::CVTQS_", SDTFPUnaryOpUnC, []>; +def Alpha_cvttq : SDNode<"AlphaISD::CVTTQ_" , SDTFPUnaryOp, []>; +def Alpha_gprello : SDNode<"AlphaISD::GPRelLo", SDTIntBinOp, []>; +def Alpha_gprelhi : SDNode<"AlphaISD::GPRelHi", SDTIntBinOp, []>; +def Alpha_rellit : SDNode<"AlphaISD::RelLit", SDTIntBinOp, [SDNPMayLoad]>; + +def retflag : SDNode<"AlphaISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInFlag]>; + +// These are target-independent nodes, but have target-specific formats. +def SDT_AlphaCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i64> ]>; +def SDT_AlphaCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i64>, + SDTCisVT<1, i64> ]>; + +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_AlphaCallSeqStart, + [SDNPHasChain, SDNPOutFlag]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_AlphaCallSeqEnd, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; + +//******************** +//Paterns for matching +//******************** +def invX : SDNodeXForm<imm, [{ //invert + return getI64Imm(~N->getZExtValue()); +}]>; +def negX : SDNodeXForm<imm, [{ //negate + return getI64Imm(~N->getZExtValue() + 1); +}]>; +def SExt32 : SDNodeXForm<imm, [{ //signed extend int to long + return getI64Imm(((int64_t)N->getZExtValue() << 32) >> 32); +}]>; +def SExt16 : SDNodeXForm<imm, [{ //signed extend int to long + return getI64Imm(((int64_t)N->getZExtValue() << 48) >> 48); +}]>; +def LL16 : SDNodeXForm<imm, [{ //lda part of constant + return getI64Imm(get_lda16(N->getZExtValue())); +}]>; +def LH16 : SDNodeXForm<imm, [{ //ldah part of constant (or more if too big) + return getI64Imm(get_ldah16(N->getZExtValue())); +}]>; +def iZAPX : SDNodeXForm<and, [{ // get imm to ZAPi + ConstantSDNode *RHS = cast<ConstantSDNode>(N->getOperand(1)); + return getI64Imm(get_zapImm(SDValue(), RHS->getZExtValue())); +}]>; +def nearP2X : SDNodeXForm<imm, [{ + return getI64Imm(Log2_64(getNearPower2((uint64_t)N->getZExtValue()))); +}]>; +def nearP2RemX : SDNodeXForm<imm, [{ + uint64_t x = + abs64(N->getZExtValue() - getNearPower2((uint64_t)N->getZExtValue())); + return getI64Imm(Log2_64(x)); +}]>; + +def immUExt8 : PatLeaf<(imm), [{ //imm fits in 8 bit zero extended field + return (uint64_t)N->getZExtValue() == (uint8_t)N->getZExtValue(); +}]>; +def immUExt8inv : PatLeaf<(imm), [{ //inverted imm fits in 8 bit zero extended field + return (uint64_t)~N->getZExtValue() == (uint8_t)~N->getZExtValue(); +}], invX>; +def immUExt8neg : PatLeaf<(imm), [{ //negated imm fits in 8 bit zero extended field + return ((uint64_t)~N->getZExtValue() + 1) == + (uint8_t)((uint64_t)~N->getZExtValue() + 1); +}], negX>; +def immSExt16 : PatLeaf<(imm), [{ //imm fits in 16 bit sign extended field + return ((int64_t)N->getZExtValue() << 48) >> 48 == + (int64_t)N->getZExtValue(); +}]>; +def immSExt16int : PatLeaf<(imm), [{ //(int)imm fits in a 16 bit sign extended field + return ((int64_t)N->getZExtValue() << 48) >> 48 == + ((int64_t)N->getZExtValue() << 32) >> 32; +}], SExt16>; + +def zappat : PatFrag<(ops node:$LHS), (and node:$LHS, imm:$L), [{ + ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N->getOperand(1)); + if (!RHS) return 0; + uint64_t build = get_zapImm(N->getOperand(0), (uint64_t)RHS->getZExtValue()); + return build != 0; +}]>; + +def immFPZ : PatLeaf<(fpimm), [{ //the only fpconstant nodes are +/- 0.0 + (void)N; // silence warning. + return true; +}]>; + +def immRem1 :PatLeaf<(imm),[{return chkRemNearPower2(N->getZExtValue(),1,0);}]>; +def immRem2 :PatLeaf<(imm),[{return chkRemNearPower2(N->getZExtValue(),2,0);}]>; +def immRem3 :PatLeaf<(imm),[{return chkRemNearPower2(N->getZExtValue(),3,0);}]>; +def immRem4 :PatLeaf<(imm),[{return chkRemNearPower2(N->getZExtValue(),4,0);}]>; +def immRem5 :PatLeaf<(imm),[{return chkRemNearPower2(N->getZExtValue(),5,0);}]>; +def immRem1n:PatLeaf<(imm),[{return chkRemNearPower2(N->getZExtValue(),1,1);}]>; +def immRem2n:PatLeaf<(imm),[{return chkRemNearPower2(N->getZExtValue(),2,1);}]>; +def immRem3n:PatLeaf<(imm),[{return chkRemNearPower2(N->getZExtValue(),3,1);}]>; +def immRem4n:PatLeaf<(imm),[{return chkRemNearPower2(N->getZExtValue(),4,1);}]>; +def immRem5n:PatLeaf<(imm),[{return chkRemNearPower2(N->getZExtValue(),5,1);}]>; + +def immRemP2n : PatLeaf<(imm), [{ + return isPowerOf2_64(getNearPower2((uint64_t)N->getZExtValue()) - + N->getZExtValue()); +}]>; +def immRemP2 : PatLeaf<(imm), [{ + return isPowerOf2_64(N->getZExtValue() - + getNearPower2((uint64_t)N->getZExtValue())); +}]>; +def immUExt8ME : PatLeaf<(imm), [{ //use this imm for mulqi + int64_t d = abs64((int64_t)N->getZExtValue() - + (int64_t)getNearPower2((uint64_t)N->getZExtValue())); + if (isPowerOf2_64(d)) return false; + switch (d) { + case 1: case 3: case 5: return false; + default: return (uint64_t)N->getZExtValue() == (uint8_t)N->getZExtValue(); + }; +}]>; + +def intop : PatFrag<(ops node:$op), (sext_inreg node:$op, i32)>; +def add4 : PatFrag<(ops node:$op1, node:$op2), + (add (shl node:$op1, 2), node:$op2)>; +def sub4 : PatFrag<(ops node:$op1, node:$op2), + (sub (shl node:$op1, 2), node:$op2)>; +def add8 : PatFrag<(ops node:$op1, node:$op2), + (add (shl node:$op1, 3), node:$op2)>; +def sub8 : PatFrag<(ops node:$op1, node:$op2), + (sub (shl node:$op1, 3), node:$op2)>; +class BinOpFrag<dag res> : PatFrag<(ops node:$LHS, node:$RHS), res>; +class CmpOpFrag<dag res> : PatFrag<(ops node:$R), res>; + +//Pseudo ops for selection + +def WTF : PseudoInstAlpha<(outs), (ins variable_ops), "#wtf", [], s_pseudo>; + +let hasCtrlDep = 1, Defs = [R30], Uses = [R30] in { +def ADJUSTSTACKUP : PseudoInstAlpha<(outs), (ins s64imm:$amt), + "; ADJUP $amt", + [(callseq_start timm:$amt)], s_pseudo>; +def ADJUSTSTACKDOWN : PseudoInstAlpha<(outs), (ins s64imm:$amt1, s64imm:$amt2), + "; ADJDOWN $amt1", + [(callseq_end timm:$amt1, timm:$amt2)], s_pseudo>; +} + +def ALTENT : PseudoInstAlpha<(outs), (ins s64imm:$TARGET), "$$$TARGET..ng:\n", [], s_pseudo>; +def PCLABEL : PseudoInstAlpha<(outs), (ins s64imm:$num), "PCMARKER_$num:\n",[], s_pseudo>; +def MEMLABEL : PseudoInstAlpha<(outs), (ins s64imm:$i, s64imm:$j, s64imm:$k, s64imm:$m), + "LSMARKER$$$i$$$j$$$k$$$m:", [], s_pseudo>; + + +let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler. +def CAS32 : PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$cmp, GPRC:$swp), "", + [(set GPRC:$dst, (atomic_cmp_swap_32 GPRC:$ptr, GPRC:$cmp, GPRC:$swp))], s_pseudo>; +def CAS64 : PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$cmp, GPRC:$swp), "", + [(set GPRC:$dst, (atomic_cmp_swap_64 GPRC:$ptr, GPRC:$cmp, GPRC:$swp))], s_pseudo>; + +def LAS32 : PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$swp), "", + [(set GPRC:$dst, (atomic_load_add_32 GPRC:$ptr, GPRC:$swp))], s_pseudo>; +def LAS64 :PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$swp), "", + [(set GPRC:$dst, (atomic_load_add_64 GPRC:$ptr, GPRC:$swp))], s_pseudo>; + +def SWAP32 : PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$swp), "", + [(set GPRC:$dst, (atomic_swap_32 GPRC:$ptr, GPRC:$swp))], s_pseudo>; +def SWAP64 :PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$swp), "", + [(set GPRC:$dst, (atomic_swap_64 GPRC:$ptr, GPRC:$swp))], s_pseudo>; +} + +//*********************** +//Real instructions +//*********************** + +//Operation Form: + +//conditional moves, int + +multiclass cmov_inst<bits<7> fun, string asmstr, PatFrag OpNode> { +def r : OForm4<0x11, fun, !strconcat(asmstr, " $RCOND,$RTRUE,$RDEST"), + [(set GPRC:$RDEST, (select (OpNode GPRC:$RCOND), GPRC:$RTRUE, GPRC:$RFALSE))], s_cmov>; +def i : OForm4L<0x11, fun, !strconcat(asmstr, " $RCOND,$RTRUE,$RDEST"), + [(set GPRC:$RDEST, (select (OpNode GPRC:$RCOND), immUExt8:$RTRUE, GPRC:$RFALSE))], s_cmov>; +} + +defm CMOVEQ : cmov_inst<0x24, "cmoveq", CmpOpFrag<(seteq node:$R, 0)>>; +defm CMOVNE : cmov_inst<0x26, "cmovne", CmpOpFrag<(setne node:$R, 0)>>; +defm CMOVLT : cmov_inst<0x44, "cmovlt", CmpOpFrag<(setlt node:$R, 0)>>; +defm CMOVLE : cmov_inst<0x64, "cmovle", CmpOpFrag<(setle node:$R, 0)>>; +defm CMOVGT : cmov_inst<0x66, "cmovgt", CmpOpFrag<(setgt node:$R, 0)>>; +defm CMOVGE : cmov_inst<0x46, "cmovge", CmpOpFrag<(setge node:$R, 0)>>; +defm CMOVLBC : cmov_inst<0x16, "cmovlbc", CmpOpFrag<(xor node:$R, 1)>>; +defm CMOVLBS : cmov_inst<0x14, "cmovlbs", CmpOpFrag<(and node:$R, 1)>>; + +//General pattern for cmov +def : Pat<(select GPRC:$which, GPRC:$src1, GPRC:$src2), + (CMOVNEr GPRC:$src2, GPRC:$src1, GPRC:$which)>; +def : Pat<(select GPRC:$which, GPRC:$src1, immUExt8:$src2), + (CMOVEQi GPRC:$src1, immUExt8:$src2, GPRC:$which)>; + +//Invert sense when we can for constants: +def : Pat<(select (setne GPRC:$RCOND, 0), GPRC:$RTRUE, immUExt8:$RFALSE), + (CMOVEQi GPRC:$RCOND, immUExt8:$RFALSE, GPRC:$RTRUE)>; +def : Pat<(select (setgt GPRC:$RCOND, 0), GPRC:$RTRUE, immUExt8:$RFALSE), + (CMOVLEi GPRC:$RCOND, immUExt8:$RFALSE, GPRC:$RTRUE)>; +def : Pat<(select (setge GPRC:$RCOND, 0), GPRC:$RTRUE, immUExt8:$RFALSE), + (CMOVLTi GPRC:$RCOND, immUExt8:$RFALSE, GPRC:$RTRUE)>; +def : Pat<(select (setlt GPRC:$RCOND, 0), GPRC:$RTRUE, immUExt8:$RFALSE), + (CMOVGEi GPRC:$RCOND, immUExt8:$RFALSE, GPRC:$RTRUE)>; +def : Pat<(select (setle GPRC:$RCOND, 0), GPRC:$RTRUE, immUExt8:$RFALSE), + (CMOVGTi GPRC:$RCOND, immUExt8:$RFALSE, GPRC:$RTRUE)>; + +multiclass all_inst<bits<6> opc, bits<7> funl, bits<7> funq, + string asmstr, PatFrag OpNode, InstrItinClass itin> { + def Lr : OForm< opc, funl, !strconcat(asmstr, "l $RA,$RB,$RC"), + [(set GPRC:$RC, (intop (OpNode GPRC:$RA, GPRC:$RB)))], itin>; + def Li : OFormL<opc, funl, !strconcat(asmstr, "l $RA,$L,$RC"), + [(set GPRC:$RC, (intop (OpNode GPRC:$RA, immUExt8:$L)))], itin>; + def Qr : OForm< opc, funq, !strconcat(asmstr, "q $RA,$RB,$RC"), + [(set GPRC:$RC, (OpNode GPRC:$RA, GPRC:$RB))], itin>; + def Qi : OFormL<opc, funq, !strconcat(asmstr, "q $RA,$L,$RC"), + [(set GPRC:$RC, (OpNode GPRC:$RA, immUExt8:$L))], itin>; +} + +defm MUL : all_inst<0x13, 0x00, 0x20, "mul", BinOpFrag<(mul node:$LHS, node:$RHS)>, s_imul>; +defm ADD : all_inst<0x10, 0x00, 0x20, "add", BinOpFrag<(add node:$LHS, node:$RHS)>, s_iadd>; +defm S4ADD : all_inst<0x10, 0x02, 0x22, "s4add", add4, s_iadd>; +defm S8ADD : all_inst<0x10, 0x12, 0x32, "s8add", add8, s_iadd>; +defm S4SUB : all_inst<0x10, 0x0B, 0x2B, "s4sub", sub4, s_iadd>; +defm S8SUB : all_inst<0x10, 0x1B, 0x3B, "s8sub", sub8, s_iadd>; +defm SUB : all_inst<0x10, 0x09, 0x29, "sub", BinOpFrag<(sub node:$LHS, node:$RHS)>, s_iadd>; +//Const cases since legalize does sub x, int -> add x, inv(int) + 1 +def : Pat<(intop (add GPRC:$RA, immUExt8neg:$L)), (SUBLi GPRC:$RA, immUExt8neg:$L)>; +def : Pat<(add GPRC:$RA, immUExt8neg:$L), (SUBQi GPRC:$RA, immUExt8neg:$L)>; +def : Pat<(intop (add4 GPRC:$RA, immUExt8neg:$L)), (S4SUBLi GPRC:$RA, immUExt8neg:$L)>; +def : Pat<(add4 GPRC:$RA, immUExt8neg:$L), (S4SUBQi GPRC:$RA, immUExt8neg:$L)>; +def : Pat<(intop (add8 GPRC:$RA, immUExt8neg:$L)), (S8SUBLi GPRC:$RA, immUExt8neg:$L)>; +def : Pat<(add8 GPRC:$RA, immUExt8neg:$L), (S8SUBQi GPRC:$RA, immUExt8neg:$L)>; + +multiclass log_inst<bits<6> opc, bits<7> fun, string asmstr, SDNode OpNode, InstrItinClass itin> { +def r : OForm<opc, fun, !strconcat(asmstr, " $RA,$RB,$RC"), + [(set GPRC:$RC, (OpNode GPRC:$RA, GPRC:$RB))], itin>; +def i : OFormL<opc, fun, !strconcat(asmstr, " $RA,$L,$RC"), + [(set GPRC:$RC, (OpNode GPRC:$RA, immUExt8:$L))], itin>; +} +multiclass inv_inst<bits<6> opc, bits<7> fun, string asmstr, SDNode OpNode, InstrItinClass itin> { +def r : OForm<opc, fun, !strconcat(asmstr, " $RA,$RB,$RC"), + [(set GPRC:$RC, (OpNode GPRC:$RA, (not GPRC:$RB)))], itin>; +def i : OFormL<opc, fun, !strconcat(asmstr, " $RA,$L,$RC"), + [(set GPRC:$RC, (OpNode GPRC:$RA, immUExt8inv:$L))], itin>; +} + +defm AND : log_inst<0x11, 0x00, "and", and, s_ilog>; +defm BIC : inv_inst<0x11, 0x08, "bic", and, s_ilog>; +defm BIS : log_inst<0x11, 0x20, "bis", or, s_ilog>; +defm ORNOT : inv_inst<0x11, 0x28, "ornot", or, s_ilog>; +defm XOR : log_inst<0x11, 0x40, "xor", xor, s_ilog>; +defm EQV : inv_inst<0x11, 0x48, "eqv", xor, s_ilog>; + +defm SL : log_inst<0x12, 0x39, "sll", shl, s_ishf>; +defm SRA : log_inst<0x12, 0x3c, "sra", sra, s_ishf>; +defm SRL : log_inst<0x12, 0x34, "srl", srl, s_ishf>; +defm UMULH : log_inst<0x13, 0x30, "umulh", mulhu, s_imul>; + +def CTLZ : OForm2<0x1C, 0x32, "CTLZ $RB,$RC", + [(set GPRC:$RC, (ctlz GPRC:$RB))], s_imisc>; +def CTPOP : OForm2<0x1C, 0x30, "CTPOP $RB,$RC", + [(set GPRC:$RC, (ctpop GPRC:$RB))], s_imisc>; +def CTTZ : OForm2<0x1C, 0x33, "CTTZ $RB,$RC", + [(set GPRC:$RC, (cttz GPRC:$RB))], s_imisc>; +def EXTBL : OForm< 0x12, 0x06, "EXTBL $RA,$RB,$RC", + [(set GPRC:$RC, (and (srl GPRC:$RA, (shl GPRC:$RB, 3)), 255))], s_ishf>; +def EXTWL : OForm< 0x12, 0x16, "EXTWL $RA,$RB,$RC", + [(set GPRC:$RC, (and (srl GPRC:$RA, (shl GPRC:$RB, 3)), 65535))], s_ishf>; +def EXTLL : OForm< 0x12, 0x26, "EXTLL $RA,$RB,$RC", + [(set GPRC:$RC, (and (srl GPRC:$RA, (shl GPRC:$RB, 3)), 4294967295))], s_ishf>; +def SEXTB : OForm2<0x1C, 0x00, "sextb $RB,$RC", + [(set GPRC:$RC, (sext_inreg GPRC:$RB, i8))], s_ishf>; +def SEXTW : OForm2<0x1C, 0x01, "sextw $RB,$RC", + [(set GPRC:$RC, (sext_inreg GPRC:$RB, i16))], s_ishf>; + +//def EXTBLi : OFormL<0x12, 0x06, "EXTBL $RA,$L,$RC", []>; //Extract byte low +//def EXTLH : OForm< 0x12, 0x6A, "EXTLH $RA,$RB,$RC", []>; //Extract longword high +//def EXTLHi : OFormL<0x12, 0x6A, "EXTLH $RA,$L,$RC", []>; //Extract longword high +//def EXTLLi : OFormL<0x12, 0x26, "EXTLL $RA,$L,$RC", []>; //Extract longword low +//def EXTQH : OForm< 0x12, 0x7A, "EXTQH $RA,$RB,$RC", []>; //Extract quadword high +//def EXTQHi : OFormL<0x12, 0x7A, "EXTQH $RA,$L,$RC", []>; //Extract quadword high +//def EXTQ : OForm< 0x12, 0x36, "EXTQ $RA,$RB,$RC", []>; //Extract quadword low +//def EXTQi : OFormL<0x12, 0x36, "EXTQ $RA,$L,$RC", []>; //Extract quadword low +//def EXTWH : OForm< 0x12, 0x5A, "EXTWH $RA,$RB,$RC", []>; //Extract word high +//def EXTWHi : OFormL<0x12, 0x5A, "EXTWH $RA,$L,$RC", []>; //Extract word high +//def EXTWLi : OFormL<0x12, 0x16, "EXTWL $RA,$L,$RC", []>; //Extract word low + +//def INSBL : OForm< 0x12, 0x0B, "INSBL $RA,$RB,$RC", []>; //Insert byte low +//def INSBLi : OFormL<0x12, 0x0B, "INSBL $RA,$L,$RC", []>; //Insert byte low +//def INSLH : OForm< 0x12, 0x67, "INSLH $RA,$RB,$RC", []>; //Insert longword high +//def INSLHi : OFormL<0x12, 0x67, "INSLH $RA,$L,$RC", []>; //Insert longword high +//def INSLL : OForm< 0x12, 0x2B, "INSLL $RA,$RB,$RC", []>; //Insert longword low +//def INSLLi : OFormL<0x12, 0x2B, "INSLL $RA,$L,$RC", []>; //Insert longword low +//def INSQH : OForm< 0x12, 0x77, "INSQH $RA,$RB,$RC", []>; //Insert quadword high +//def INSQHi : OFormL<0x12, 0x77, "INSQH $RA,$L,$RC", []>; //Insert quadword high +//def INSQL : OForm< 0x12, 0x3B, "INSQL $RA,$RB,$RC", []>; //Insert quadword low +//def INSQLi : OFormL<0x12, 0x3B, "INSQL $RA,$L,$RC", []>; //Insert quadword low +//def INSWH : OForm< 0x12, 0x57, "INSWH $RA,$RB,$RC", []>; //Insert word high +//def INSWHi : OFormL<0x12, 0x57, "INSWH $RA,$L,$RC", []>; //Insert word high +//def INSWL : OForm< 0x12, 0x1B, "INSWL $RA,$RB,$RC", []>; //Insert word low +//def INSWLi : OFormL<0x12, 0x1B, "INSWL $RA,$L,$RC", []>; //Insert word low + +//def MSKBL : OForm< 0x12, 0x02, "MSKBL $RA,$RB,$RC", []>; //Mask byte low +//def MSKBLi : OFormL<0x12, 0x02, "MSKBL $RA,$L,$RC", []>; //Mask byte low +//def MSKLH : OForm< 0x12, 0x62, "MSKLH $RA,$RB,$RC", []>; //Mask longword high +//def MSKLHi : OFormL<0x12, 0x62, "MSKLH $RA,$L,$RC", []>; //Mask longword high +//def MSKLL : OForm< 0x12, 0x22, "MSKLL $RA,$RB,$RC", []>; //Mask longword low +//def MSKLLi : OFormL<0x12, 0x22, "MSKLL $RA,$L,$RC", []>; //Mask longword low +//def MSKQH : OForm< 0x12, 0x72, "MSKQH $RA,$RB,$RC", []>; //Mask quadword high +//def MSKQHi : OFormL<0x12, 0x72, "MSKQH $RA,$L,$RC", []>; //Mask quadword high +//def MSKQL : OForm< 0x12, 0x32, "MSKQL $RA,$RB,$RC", []>; //Mask quadword low +//def MSKQLi : OFormL<0x12, 0x32, "MSKQL $RA,$L,$RC", []>; //Mask quadword low +//def MSKWH : OForm< 0x12, 0x52, "MSKWH $RA,$RB,$RC", []>; //Mask word high +//def MSKWHi : OFormL<0x12, 0x52, "MSKWH $RA,$L,$RC", []>; //Mask word high +//def MSKWL : OForm< 0x12, 0x12, "MSKWL $RA,$RB,$RC", []>; //Mask word low +//def MSKWLi : OFormL<0x12, 0x12, "MSKWL $RA,$L,$RC", []>; //Mask word low + +def ZAPNOTi : OFormL<0x12, 0x31, "zapnot $RA,$L,$RC", [], s_ishf>; + +// Define the pattern that produces ZAPNOTi. +def : Pat<(zappat:$imm GPRC:$RA), + (ZAPNOTi GPRC:$RA, (iZAPX GPRC:$imm))>; + + +//Comparison, int +//So this is a waste of what this instruction can do, but it still saves something +def CMPBGE : OForm< 0x10, 0x0F, "cmpbge $RA,$RB,$RC", + [(set GPRC:$RC, (setuge (and GPRC:$RA, 255), (and GPRC:$RB, 255)))], s_ilog>; +def CMPBGEi : OFormL<0x10, 0x0F, "cmpbge $RA,$L,$RC", + [(set GPRC:$RC, (setuge (and GPRC:$RA, 255), immUExt8:$L))], s_ilog>; +def CMPEQ : OForm< 0x10, 0x2D, "cmpeq $RA,$RB,$RC", + [(set GPRC:$RC, (seteq GPRC:$RA, GPRC:$RB))], s_iadd>; +def CMPEQi : OFormL<0x10, 0x2D, "cmpeq $RA,$L,$RC", + [(set GPRC:$RC, (seteq GPRC:$RA, immUExt8:$L))], s_iadd>; +def CMPLE : OForm< 0x10, 0x6D, "cmple $RA,$RB,$RC", + [(set GPRC:$RC, (setle GPRC:$RA, GPRC:$RB))], s_iadd>; +def CMPLEi : OFormL<0x10, 0x6D, "cmple $RA,$L,$RC", + [(set GPRC:$RC, (setle GPRC:$RA, immUExt8:$L))], s_iadd>; +def CMPLT : OForm< 0x10, 0x4D, "cmplt $RA,$RB,$RC", + [(set GPRC:$RC, (setlt GPRC:$RA, GPRC:$RB))], s_iadd>; +def CMPLTi : OFormL<0x10, 0x4D, "cmplt $RA,$L,$RC", + [(set GPRC:$RC, (setlt GPRC:$RA, immUExt8:$L))], s_iadd>; +def CMPULE : OForm< 0x10, 0x3D, "cmpule $RA,$RB,$RC", + [(set GPRC:$RC, (setule GPRC:$RA, GPRC:$RB))], s_iadd>; +def CMPULEi : OFormL<0x10, 0x3D, "cmpule $RA,$L,$RC", + [(set GPRC:$RC, (setule GPRC:$RA, immUExt8:$L))], s_iadd>; +def CMPULT : OForm< 0x10, 0x1D, "cmpult $RA,$RB,$RC", + [(set GPRC:$RC, (setult GPRC:$RA, GPRC:$RB))], s_iadd>; +def CMPULTi : OFormL<0x10, 0x1D, "cmpult $RA,$L,$RC", + [(set GPRC:$RC, (setult GPRC:$RA, immUExt8:$L))], s_iadd>; + +//Patterns for unsupported int comparisons +def : Pat<(setueq GPRC:$X, GPRC:$Y), (CMPEQ GPRC:$X, GPRC:$Y)>; +def : Pat<(setueq GPRC:$X, immUExt8:$Y), (CMPEQi GPRC:$X, immUExt8:$Y)>; + +def : Pat<(setugt GPRC:$X, GPRC:$Y), (CMPULT GPRC:$Y, GPRC:$X)>; +def : Pat<(setugt immUExt8:$X, GPRC:$Y), (CMPULTi GPRC:$Y, immUExt8:$X)>; + +def : Pat<(setuge GPRC:$X, GPRC:$Y), (CMPULE GPRC:$Y, GPRC:$X)>; +def : Pat<(setuge immUExt8:$X, GPRC:$Y), (CMPULEi GPRC:$Y, immUExt8:$X)>; + +def : Pat<(setgt GPRC:$X, GPRC:$Y), (CMPLT GPRC:$Y, GPRC:$X)>; +def : Pat<(setgt immUExt8:$X, GPRC:$Y), (CMPLTi GPRC:$Y, immUExt8:$X)>; + +def : Pat<(setge GPRC:$X, GPRC:$Y), (CMPLE GPRC:$Y, GPRC:$X)>; +def : Pat<(setge immUExt8:$X, GPRC:$Y), (CMPLEi GPRC:$Y, immUExt8:$X)>; + +def : Pat<(setne GPRC:$X, GPRC:$Y), (CMPEQi (CMPEQ GPRC:$X, GPRC:$Y), 0)>; +def : Pat<(setne GPRC:$X, immUExt8:$Y), (CMPEQi (CMPEQi GPRC:$X, immUExt8:$Y), 0)>; + +def : Pat<(setune GPRC:$X, GPRC:$Y), (CMPEQi (CMPEQ GPRC:$X, GPRC:$Y), 0)>; +def : Pat<(setune GPRC:$X, immUExt8:$Y), (CMPEQi (CMPEQ GPRC:$X, immUExt8:$Y), 0)>; + + +let isReturn = 1, isTerminator = 1, Ra = 31, Rb = 26, disp = 1, Uses = [R26] in { + def RETDAG : MbrForm< 0x1A, 0x02, (ops), "ret $$31,($$26),1", s_jsr>; //Return from subroutine + def RETDAGp : MbrpForm< 0x1A, 0x02, (ops), "ret $$31,($$26),1", [(retflag)], s_jsr>; //Return from subroutine +} + +let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1, Ra = 31, disp = 0 in +def JMP : MbrpForm< 0x1A, 0x00, (ops GPRC:$RS), "jmp $$31,($RS),0", + [(brind GPRC:$RS)], s_jsr>; //Jump + +let isCall = 1, Ra = 26, + Defs = [R0, R1, R2, R3, R4, R5, R6, R7, R8, R16, R17, R18, R19, + R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, + F0, F1, + F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, + F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30], Uses = [R29] in { + def BSR : BFormD<0x34, "bsr $$26,$$$DISP..ng", [], s_jsr>; //Branch to subroutine +} +let isCall = 1, Ra = 26, Rb = 27, disp = 0, + Defs = [R0, R1, R2, R3, R4, R5, R6, R7, R8, R16, R17, R18, R19, + R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, + F0, F1, + F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, + F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30], Uses = [R27, R29] in { + def JSR : MbrForm< 0x1A, 0x01, (ops ), "jsr $$26,($$27),0", s_jsr>; //Jump to subroutine +} + +let isCall = 1, Ra = 23, Rb = 27, disp = 0, + Defs = [R23, R24, R25, R27, R28], Uses = [R24, R25, R27] in + def JSRs : MbrForm< 0x1A, 0x01, (ops ), "jsr $$23,($$27),0", s_jsr>; //Jump to div or rem + + +def JSR_COROUTINE : MbrForm< 0x1A, 0x03, (ops GPRC:$RD, GPRC:$RS, s14imm:$DISP), "jsr_coroutine $RD,($RS),$DISP", s_jsr>; //Jump to subroutine return + + +let OutOperandList = (ops GPRC:$RA), InOperandList = (ops s64imm:$DISP, GPRC:$RB) in { +def LDQ : MForm<0x29, 1, "ldq $RA,$DISP($RB)", + [(set GPRC:$RA, (load (add GPRC:$RB, immSExt16:$DISP)))], s_ild>; +def LDQr : MForm<0x29, 1, "ldq $RA,$DISP($RB)\t\t!gprellow", + [(set GPRC:$RA, (load (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB)))], s_ild>; +def LDL : MForm<0x28, 1, "ldl $RA,$DISP($RB)", + [(set GPRC:$RA, (sextloadi32 (add GPRC:$RB, immSExt16:$DISP)))], s_ild>; +def LDLr : MForm<0x28, 1, "ldl $RA,$DISP($RB)\t\t!gprellow", + [(set GPRC:$RA, (sextloadi32 (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB)))], s_ild>; +def LDBU : MForm<0x0A, 1, "ldbu $RA,$DISP($RB)", + [(set GPRC:$RA, (zextloadi8 (add GPRC:$RB, immSExt16:$DISP)))], s_ild>; +def LDBUr : MForm<0x0A, 1, "ldbu $RA,$DISP($RB)\t\t!gprellow", + [(set GPRC:$RA, (zextloadi8 (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB)))], s_ild>; +def LDWU : MForm<0x0C, 1, "ldwu $RA,$DISP($RB)", + [(set GPRC:$RA, (zextloadi16 (add GPRC:$RB, immSExt16:$DISP)))], s_ild>; +def LDWUr : MForm<0x0C, 1, "ldwu $RA,$DISP($RB)\t\t!gprellow", + [(set GPRC:$RA, (zextloadi16 (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB)))], s_ild>; +} + + +let OutOperandList = (ops), InOperandList = (ops GPRC:$RA, s64imm:$DISP, GPRC:$RB) in { +def STB : MForm<0x0E, 0, "stb $RA,$DISP($RB)", + [(truncstorei8 GPRC:$RA, (add GPRC:$RB, immSExt16:$DISP))], s_ist>; +def STBr : MForm<0x0E, 0, "stb $RA,$DISP($RB)\t\t!gprellow", + [(truncstorei8 GPRC:$RA, (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB))], s_ist>; +def STW : MForm<0x0D, 0, "stw $RA,$DISP($RB)", + [(truncstorei16 GPRC:$RA, (add GPRC:$RB, immSExt16:$DISP))], s_ist>; +def STWr : MForm<0x0D, 0, "stw $RA,$DISP($RB)\t\t!gprellow", + [(truncstorei16 GPRC:$RA, (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB))], s_ist>; +def STL : MForm<0x2C, 0, "stl $RA,$DISP($RB)", + [(truncstorei32 GPRC:$RA, (add GPRC:$RB, immSExt16:$DISP))], s_ist>; +def STLr : MForm<0x2C, 0, "stl $RA,$DISP($RB)\t\t!gprellow", + [(truncstorei32 GPRC:$RA, (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB))], s_ist>; +def STQ : MForm<0x2D, 0, "stq $RA,$DISP($RB)", + [(store GPRC:$RA, (add GPRC:$RB, immSExt16:$DISP))], s_ist>; +def STQr : MForm<0x2D, 0, "stq $RA,$DISP($RB)\t\t!gprellow", + [(store GPRC:$RA, (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB))], s_ist>; +} + +//Load address +let OutOperandList = (ops GPRC:$RA), InOperandList = (ops s64imm:$DISP, GPRC:$RB) in { +def LDA : MForm<0x08, 0, "lda $RA,$DISP($RB)", + [(set GPRC:$RA, (add GPRC:$RB, immSExt16:$DISP))], s_lda>; +def LDAr : MForm<0x08, 0, "lda $RA,$DISP($RB)\t\t!gprellow", + [(set GPRC:$RA, (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB))], s_lda>; //Load address +def LDAH : MForm<0x09, 0, "ldah $RA,$DISP($RB)", + [], s_lda>; //Load address high +def LDAHr : MForm<0x09, 0, "ldah $RA,$DISP($RB)\t\t!gprelhigh", + [(set GPRC:$RA, (Alpha_gprelhi tglobaladdr:$DISP, GPRC:$RB))], s_lda>; //Load address high +} + +let OutOperandList = (ops), InOperandList = (ops F4RC:$RA, s64imm:$DISP, GPRC:$RB) in { +def STS : MForm<0x26, 0, "sts $RA,$DISP($RB)", + [(store F4RC:$RA, (add GPRC:$RB, immSExt16:$DISP))], s_fst>; +def STSr : MForm<0x26, 0, "sts $RA,$DISP($RB)\t\t!gprellow", + [(store F4RC:$RA, (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB))], s_fst>; +} +let OutOperandList = (ops F4RC:$RA), InOperandList = (ops s64imm:$DISP, GPRC:$RB) in { +def LDS : MForm<0x22, 1, "lds $RA,$DISP($RB)", + [(set F4RC:$RA, (load (add GPRC:$RB, immSExt16:$DISP)))], s_fld>; +def LDSr : MForm<0x22, 1, "lds $RA,$DISP($RB)\t\t!gprellow", + [(set F4RC:$RA, (load (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB)))], s_fld>; +} +let OutOperandList = (ops), InOperandList = (ops F8RC:$RA, s64imm:$DISP, GPRC:$RB) in { +def STT : MForm<0x27, 0, "stt $RA,$DISP($RB)", + [(store F8RC:$RA, (add GPRC:$RB, immSExt16:$DISP))], s_fst>; +def STTr : MForm<0x27, 0, "stt $RA,$DISP($RB)\t\t!gprellow", + [(store F8RC:$RA, (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB))], s_fst>; +} +let OutOperandList = (ops F8RC:$RA), InOperandList = (ops s64imm:$DISP, GPRC:$RB) in { +def LDT : MForm<0x23, 1, "ldt $RA,$DISP($RB)", + [(set F8RC:$RA, (load (add GPRC:$RB, immSExt16:$DISP)))], s_fld>; +def LDTr : MForm<0x23, 1, "ldt $RA,$DISP($RB)\t\t!gprellow", + [(set F8RC:$RA, (load (Alpha_gprello tglobaladdr:$DISP, GPRC:$RB)))], s_fld>; +} + + +//constpool rels +def : Pat<(i64 (load (Alpha_gprello tconstpool:$DISP, GPRC:$RB))), + (LDQr tconstpool:$DISP, GPRC:$RB)>; +def : Pat<(i64 (sextloadi32 (Alpha_gprello tconstpool:$DISP, GPRC:$RB))), + (LDLr tconstpool:$DISP, GPRC:$RB)>; +def : Pat<(i64 (zextloadi8 (Alpha_gprello tconstpool:$DISP, GPRC:$RB))), + (LDBUr tconstpool:$DISP, GPRC:$RB)>; +def : Pat<(i64 (zextloadi16 (Alpha_gprello tconstpool:$DISP, GPRC:$RB))), + (LDWUr tconstpool:$DISP, GPRC:$RB)>; +def : Pat<(i64 (Alpha_gprello tconstpool:$DISP, GPRC:$RB)), + (LDAr tconstpool:$DISP, GPRC:$RB)>; +def : Pat<(i64 (Alpha_gprelhi tconstpool:$DISP, GPRC:$RB)), + (LDAHr tconstpool:$DISP, GPRC:$RB)>; +def : Pat<(f32 (load (Alpha_gprello tconstpool:$DISP, GPRC:$RB))), + (LDSr tconstpool:$DISP, GPRC:$RB)>; +def : Pat<(f64 (load (Alpha_gprello tconstpool:$DISP, GPRC:$RB))), + (LDTr tconstpool:$DISP, GPRC:$RB)>; + +//jumptable rels +def : Pat<(i64 (Alpha_gprelhi tjumptable:$DISP, GPRC:$RB)), + (LDAHr tjumptable:$DISP, GPRC:$RB)>; +def : Pat<(i64 (Alpha_gprello tjumptable:$DISP, GPRC:$RB)), + (LDAr tjumptable:$DISP, GPRC:$RB)>; + + +//misc ext patterns +def : Pat<(i64 (extloadi8 (add GPRC:$RB, immSExt16:$DISP))), + (LDBU immSExt16:$DISP, GPRC:$RB)>; +def : Pat<(i64 (extloadi16 (add GPRC:$RB, immSExt16:$DISP))), + (LDWU immSExt16:$DISP, GPRC:$RB)>; +def : Pat<(i64 (extloadi32 (add GPRC:$RB, immSExt16:$DISP))), + (LDL immSExt16:$DISP, GPRC:$RB)>; + +//0 disp patterns +def : Pat<(i64 (load GPRC:$addr)), + (LDQ 0, GPRC:$addr)>; +def : Pat<(f64 (load GPRC:$addr)), + (LDT 0, GPRC:$addr)>; +def : Pat<(f32 (load GPRC:$addr)), + (LDS 0, GPRC:$addr)>; +def : Pat<(i64 (sextloadi32 GPRC:$addr)), + (LDL 0, GPRC:$addr)>; +def : Pat<(i64 (zextloadi16 GPRC:$addr)), + (LDWU 0, GPRC:$addr)>; +def : Pat<(i64 (zextloadi8 GPRC:$addr)), + (LDBU 0, GPRC:$addr)>; +def : Pat<(i64 (extloadi8 GPRC:$addr)), + (LDBU 0, GPRC:$addr)>; +def : Pat<(i64 (extloadi16 GPRC:$addr)), + (LDWU 0, GPRC:$addr)>; +def : Pat<(i64 (extloadi32 GPRC:$addr)), + (LDL 0, GPRC:$addr)>; + +def : Pat<(store GPRC:$DATA, GPRC:$addr), + (STQ GPRC:$DATA, 0, GPRC:$addr)>; +def : Pat<(store F8RC:$DATA, GPRC:$addr), + (STT F8RC:$DATA, 0, GPRC:$addr)>; +def : Pat<(store F4RC:$DATA, GPRC:$addr), + (STS F4RC:$DATA, 0, GPRC:$addr)>; +def : Pat<(truncstorei32 GPRC:$DATA, GPRC:$addr), + (STL GPRC:$DATA, 0, GPRC:$addr)>; +def : Pat<(truncstorei16 GPRC:$DATA, GPRC:$addr), + (STW GPRC:$DATA, 0, GPRC:$addr)>; +def : Pat<(truncstorei8 GPRC:$DATA, GPRC:$addr), + (STB GPRC:$DATA, 0, GPRC:$addr)>; + + +//load address, rellocated gpdist form +let OutOperandList = (ops GPRC:$RA), + InOperandList = (ops s16imm:$DISP, GPRC:$RB, s16imm:$NUM), + mayLoad = 1 in { +def LDAg : MForm<0x08, 1, "lda $RA,0($RB)\t\t!gpdisp!$NUM", [], s_lda>; //Load address +def LDAHg : MForm<0x09, 1, "ldah $RA,0($RB)\t\t!gpdisp!$NUM", [], s_lda>; //Load address +} + +//Load quad, rellocated literal form +let OutOperandList = (ops GPRC:$RA), InOperandList = (ops s64imm:$DISP, GPRC:$RB) in +def LDQl : MForm<0x29, 1, "ldq $RA,$DISP($RB)\t\t!literal", + [(set GPRC:$RA, (Alpha_rellit tglobaladdr:$DISP, GPRC:$RB))], s_ild>; +def : Pat<(Alpha_rellit texternalsym:$ext, GPRC:$RB), + (LDQl texternalsym:$ext, GPRC:$RB)>; + +let OutOperandList = (outs GPRC:$RR), + InOperandList = (ins GPRC:$RA, s64imm:$DISP, GPRC:$RB), + Constraints = "$RA = $RR", + DisableEncoding = "$RR" in { +def STQ_C : MForm<0x2F, 0, "stq_l $RA,$DISP($RB)", [], s_ist>; +def STL_C : MForm<0x2E, 0, "stl_l $RA,$DISP($RB)", [], s_ist>; +} +let OutOperandList = (ops GPRC:$RA), + InOperandList = (ops s64imm:$DISP, GPRC:$RB), + mayLoad = 1 in { +def LDQ_L : MForm<0x2B, 1, "ldq_l $RA,$DISP($RB)", [], s_ild>; +def LDL_L : MForm<0x2A, 1, "ldl_l $RA,$DISP($RB)", [], s_ild>; +} + +def RPCC : MfcForm<0x18, 0xC000, "rpcc $RA", s_rpcc>; //Read process cycle counter +def MB : MfcPForm<0x18, 0x4000, "mb", s_imisc>; //memory barrier +def WMB : MfcPForm<0x18, 0x4400, "wmb", s_imisc>; //write memory barrier + +def : Pat<(membarrier (i64 imm:$ll), (i64 imm:$ls), (i64 imm:$sl), (i64 1), (i64 imm:$dev)), + (WMB)>; +def : Pat<(membarrier (i64 imm:$ll), (i64 imm:$ls), (i64 imm:$sl), (i64 imm:$ss), (i64 imm:$dev)), + (MB)>; + +//Basic Floating point ops + +//Floats + +let OutOperandList = (ops F4RC:$RC), InOperandList = (ops F4RC:$RB), Fa = 31 in +def SQRTS : FPForm<0x14, 0x58B, "sqrts/su $RB,$RC", + [(set F4RC:$RC, (fsqrt F4RC:$RB))], s_fsqrts>; + +let OutOperandList = (ops F4RC:$RC), InOperandList = (ops F4RC:$RA, F4RC:$RB) in { +def ADDS : FPForm<0x16, 0x580, "adds/su $RA,$RB,$RC", + [(set F4RC:$RC, (fadd F4RC:$RA, F4RC:$RB))], s_fadd>; +def SUBS : FPForm<0x16, 0x581, "subs/su $RA,$RB,$RC", + [(set F4RC:$RC, (fsub F4RC:$RA, F4RC:$RB))], s_fadd>; +def DIVS : FPForm<0x16, 0x583, "divs/su $RA,$RB,$RC", + [(set F4RC:$RC, (fdiv F4RC:$RA, F4RC:$RB))], s_fdivs>; +def MULS : FPForm<0x16, 0x582, "muls/su $RA,$RB,$RC", + [(set F4RC:$RC, (fmul F4RC:$RA, F4RC:$RB))], s_fmul>; + +def CPYSS : FPForm<0x17, 0x020, "cpys $RA,$RB,$RC", + [(set F4RC:$RC, (fcopysign F4RC:$RB, F4RC:$RA))], s_fadd>; +def CPYSES : FPForm<0x17, 0x022, "cpyse $RA,$RB,$RC",[], s_fadd>; //Copy sign and exponent +def CPYSNS : FPForm<0x17, 0x021, "cpysn $RA,$RB,$RC", + [(set F4RC:$RC, (fneg (fcopysign F4RC:$RB, F4RC:$RA)))], s_fadd>; +} + +//Doubles + +let OutOperandList = (ops F8RC:$RC), InOperandList = (ops F8RC:$RB), Fa = 31 in +def SQRTT : FPForm<0x14, 0x5AB, "sqrtt/su $RB,$RC", + [(set F8RC:$RC, (fsqrt F8RC:$RB))], s_fsqrtt>; + +let OutOperandList = (ops F8RC:$RC), InOperandList = (ops F8RC:$RA, F8RC:$RB) in { +def ADDT : FPForm<0x16, 0x5A0, "addt/su $RA,$RB,$RC", + [(set F8RC:$RC, (fadd F8RC:$RA, F8RC:$RB))], s_fadd>; +def SUBT : FPForm<0x16, 0x5A1, "subt/su $RA,$RB,$RC", + [(set F8RC:$RC, (fsub F8RC:$RA, F8RC:$RB))], s_fadd>; +def DIVT : FPForm<0x16, 0x5A3, "divt/su $RA,$RB,$RC", + [(set F8RC:$RC, (fdiv F8RC:$RA, F8RC:$RB))], s_fdivt>; +def MULT : FPForm<0x16, 0x5A2, "mult/su $RA,$RB,$RC", + [(set F8RC:$RC, (fmul F8RC:$RA, F8RC:$RB))], s_fmul>; + +def CPYST : FPForm<0x17, 0x020, "cpys $RA,$RB,$RC", + [(set F8RC:$RC, (fcopysign F8RC:$RB, F8RC:$RA))], s_fadd>; +def CPYSET : FPForm<0x17, 0x022, "cpyse $RA,$RB,$RC",[], s_fadd>; //Copy sign and exponent +def CPYSNT : FPForm<0x17, 0x021, "cpysn $RA,$RB,$RC", + [(set F8RC:$RC, (fneg (fcopysign F8RC:$RB, F8RC:$RA)))], s_fadd>; + +def CMPTEQ : FPForm<0x16, 0x5A5, "cmpteq/su $RA,$RB,$RC", [], s_fadd>; +// [(set F8RC:$RC, (seteq F8RC:$RA, F8RC:$RB))]>; +def CMPTLE : FPForm<0x16, 0x5A7, "cmptle/su $RA,$RB,$RC", [], s_fadd>; +// [(set F8RC:$RC, (setle F8RC:$RA, F8RC:$RB))]>; +def CMPTLT : FPForm<0x16, 0x5A6, "cmptlt/su $RA,$RB,$RC", [], s_fadd>; +// [(set F8RC:$RC, (setlt F8RC:$RA, F8RC:$RB))]>; +def CMPTUN : FPForm<0x16, 0x5A4, "cmptun/su $RA,$RB,$RC", [], s_fadd>; +// [(set F8RC:$RC, (setuo F8RC:$RA, F8RC:$RB))]>; +} + +//More CPYS forms: +let OutOperandList = (ops F8RC:$RC), InOperandList = (ops F4RC:$RA, F8RC:$RB) in { +def CPYSTs : FPForm<0x17, 0x020, "cpys $RA,$RB,$RC", + [(set F8RC:$RC, (fcopysign F8RC:$RB, F4RC:$RA))], s_fadd>; +def CPYSNTs : FPForm<0x17, 0x021, "cpysn $RA,$RB,$RC", + [(set F8RC:$RC, (fneg (fcopysign F8RC:$RB, F4RC:$RA)))], s_fadd>; +} +let OutOperandList = (ops F4RC:$RC), InOperandList = (ops F8RC:$RA, F4RC:$RB) in { +def CPYSSt : FPForm<0x17, 0x020, "cpys $RA,$RB,$RC", + [(set F4RC:$RC, (fcopysign F4RC:$RB, F8RC:$RA))], s_fadd>; +def CPYSESt : FPForm<0x17, 0x022, "cpyse $RA,$RB,$RC",[], s_fadd>; //Copy sign and exponent +def CPYSNSt : FPForm<0x17, 0x021, "cpysn $RA,$RB,$RC", + [(set F4RC:$RC, (fneg (fcopysign F4RC:$RB, F8RC:$RA)))], s_fadd>; +} + +//conditional moves, floats +let OutOperandList = (ops F4RC:$RDEST), InOperandList = (ops F4RC:$RFALSE, F4RC:$RTRUE, F8RC:$RCOND), + isTwoAddress = 1 in { +def FCMOVEQS : FPForm<0x17, 0x02A, "fcmoveq $RCOND,$RTRUE,$RDEST",[], s_fcmov>; //FCMOVE if = zero +def FCMOVGES : FPForm<0x17, 0x02D, "fcmovge $RCOND,$RTRUE,$RDEST",[], s_fcmov>; //FCMOVE if >= zero +def FCMOVGTS : FPForm<0x17, 0x02F, "fcmovgt $RCOND,$RTRUE,$RDEST",[], s_fcmov>; //FCMOVE if > zero +def FCMOVLES : FPForm<0x17, 0x02E, "fcmovle $RCOND,$RTRUE,$RDEST",[], s_fcmov>; //FCMOVE if <= zero +def FCMOVLTS : FPForm<0x17, 0x02C, "fcmovlt $RCOND,$RTRUE,$RDEST",[], s_fcmov>; // FCMOVE if < zero +def FCMOVNES : FPForm<0x17, 0x02B, "fcmovne $RCOND,$RTRUE,$RDEST",[], s_fcmov>; //FCMOVE if != zero +} +//conditional moves, doubles +let OutOperandList = (ops F8RC:$RDEST), InOperandList = (ops F8RC:$RFALSE, F8RC:$RTRUE, F8RC:$RCOND), + isTwoAddress = 1 in { +def FCMOVEQT : FPForm<0x17, 0x02A, "fcmoveq $RCOND,$RTRUE,$RDEST", [], s_fcmov>; +def FCMOVGET : FPForm<0x17, 0x02D, "fcmovge $RCOND,$RTRUE,$RDEST", [], s_fcmov>; +def FCMOVGTT : FPForm<0x17, 0x02F, "fcmovgt $RCOND,$RTRUE,$RDEST", [], s_fcmov>; +def FCMOVLET : FPForm<0x17, 0x02E, "fcmovle $RCOND,$RTRUE,$RDEST", [], s_fcmov>; +def FCMOVLTT : FPForm<0x17, 0x02C, "fcmovlt $RCOND,$RTRUE,$RDEST", [], s_fcmov>; +def FCMOVNET : FPForm<0x17, 0x02B, "fcmovne $RCOND,$RTRUE,$RDEST", [], s_fcmov>; +} + +//misc FP selects +//Select double + +def : Pat<(select (seteq F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setoeq F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setueq F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; + +def : Pat<(select (setne F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVEQT F8RC:$sf, F8RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setone F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVEQT F8RC:$sf, F8RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setune F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVEQT F8RC:$sf, F8RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; + +def : Pat<(select (setgt F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLT F8RC:$RB, F8RC:$RA))>; +def : Pat<(select (setogt F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLT F8RC:$RB, F8RC:$RA))>; +def : Pat<(select (setugt F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLT F8RC:$RB, F8RC:$RA))>; + +def : Pat<(select (setge F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLE F8RC:$RB, F8RC:$RA))>; +def : Pat<(select (setoge F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLE F8RC:$RB, F8RC:$RA))>; +def : Pat<(select (setuge F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLE F8RC:$RB, F8RC:$RA))>; + +def : Pat<(select (setlt F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLT F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setolt F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLT F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setult F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLT F8RC:$RA, F8RC:$RB))>; + +def : Pat<(select (setle F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLE F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setole F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLE F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setule F8RC:$RA, F8RC:$RB), F8RC:$st, F8RC:$sf), + (FCMOVNET F8RC:$sf, F8RC:$st, (CMPTLE F8RC:$RA, F8RC:$RB))>; + +//Select single +def : Pat<(select (seteq F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setoeq F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setueq F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; + +def : Pat<(select (setne F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVEQS F4RC:$sf, F4RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setone F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVEQS F4RC:$sf, F4RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setune F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVEQS F4RC:$sf, F4RC:$st, (CMPTEQ F8RC:$RA, F8RC:$RB))>; + +def : Pat<(select (setgt F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLT F8RC:$RB, F8RC:$RA))>; +def : Pat<(select (setogt F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLT F8RC:$RB, F8RC:$RA))>; +def : Pat<(select (setugt F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLT F8RC:$RB, F8RC:$RA))>; + +def : Pat<(select (setge F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLE F8RC:$RB, F8RC:$RA))>; +def : Pat<(select (setoge F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLE F8RC:$RB, F8RC:$RA))>; +def : Pat<(select (setuge F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLE F8RC:$RB, F8RC:$RA))>; + +def : Pat<(select (setlt F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLT F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setolt F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLT F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setult F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLT F8RC:$RA, F8RC:$RB))>; + +def : Pat<(select (setle F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLE F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setole F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLE F8RC:$RA, F8RC:$RB))>; +def : Pat<(select (setule F8RC:$RA, F8RC:$RB), F4RC:$st, F4RC:$sf), + (FCMOVNES F4RC:$sf, F4RC:$st, (CMPTLE F8RC:$RA, F8RC:$RB))>; + + + +let OutOperandList = (ops GPRC:$RC), InOperandList = (ops F4RC:$RA), Fb = 31 in +def FTOIS : FPForm<0x1C, 0x078, "ftois $RA,$RC",[], s_ftoi>; //Floating to integer move, S_floating +let OutOperandList = (ops GPRC:$RC), InOperandList = (ops F8RC:$RA), Fb = 31 in +def FTOIT : FPForm<0x1C, 0x070, "ftoit $RA,$RC", + [(set GPRC:$RC, (bitconvert F8RC:$RA))], s_ftoi>; //Floating to integer move +let OutOperandList = (ops F4RC:$RC), InOperandList = (ops GPRC:$RA), Fb = 31 in +def ITOFS : FPForm<0x14, 0x004, "itofs $RA,$RC",[], s_itof>; //Integer to floating move, S_floating +let OutOperandList = (ops F8RC:$RC), InOperandList = (ops GPRC:$RA), Fb = 31 in +def ITOFT : FPForm<0x14, 0x024, "itoft $RA,$RC", + [(set F8RC:$RC, (bitconvert GPRC:$RA))], s_itof>; //Integer to floating move + + +let OutOperandList = (ops F4RC:$RC), InOperandList = (ops F8RC:$RB), Fa = 31 in +def CVTQS : FPForm<0x16, 0x7BC, "cvtqs/sui $RB,$RC", + [(set F4RC:$RC, (Alpha_cvtqs F8RC:$RB))], s_fadd>; +let OutOperandList = (ops F8RC:$RC), InOperandList = (ops F8RC:$RB), Fa = 31 in +def CVTQT : FPForm<0x16, 0x7BE, "cvtqt/sui $RB,$RC", + [(set F8RC:$RC, (Alpha_cvtqt F8RC:$RB))], s_fadd>; +let OutOperandList = (ops F8RC:$RC), InOperandList = (ops F8RC:$RB), Fa = 31 in +def CVTTQ : FPForm<0x16, 0x52F, "cvttq/svc $RB,$RC", + [(set F8RC:$RC, (Alpha_cvttq F8RC:$RB))], s_fadd>; +let OutOperandList = (ops F8RC:$RC), InOperandList = (ops F4RC:$RB), Fa = 31 in +def CVTST : FPForm<0x16, 0x6AC, "cvtst/s $RB,$RC", + [(set F8RC:$RC, (fextend F4RC:$RB))], s_fadd>; +let OutOperandList = (ops F4RC:$RC), InOperandList = (ops F8RC:$RB), Fa = 31 in +def CVTTS : FPForm<0x16, 0x7AC, "cvtts/sui $RB,$RC", + [(set F4RC:$RC, (fround F8RC:$RB))], s_fadd>; + + +///////////////////////////////////////////////////////// +//Branching +///////////////////////////////////////////////////////// +class br_icc<bits<6> opc, string asmstr> + : BFormN<opc, (ops u64imm:$opc, GPRC:$R, target:$dst), + !strconcat(asmstr, " $R,$dst"), s_icbr>; +class br_fcc<bits<6> opc, string asmstr> + : BFormN<opc, (ops u64imm:$opc, F8RC:$R, target:$dst), + !strconcat(asmstr, " $R,$dst"), s_fbr>; + +let isBranch = 1, isTerminator = 1, hasCtrlDep = 1 in { +let Ra = 31 in +def BR : BFormD<0x30, "br $$31,$DISP", [(br bb:$DISP)], s_ubr>; + +def COND_BRANCH_I : BFormN<0, (ops u64imm:$opc, GPRC:$R, target:$dst), + "{:comment} COND_BRANCH imm:$opc, GPRC:$R, bb:$dst", + s_icbr>; +def COND_BRANCH_F : BFormN<0, (ops u64imm:$opc, F8RC:$R, target:$dst), + "{:comment} COND_BRANCH imm:$opc, F8RC:$R, bb:$dst", + s_fbr>; +//Branches, int +def BEQ : br_icc<0x39, "beq">; +def BGE : br_icc<0x3E, "bge">; +def BGT : br_icc<0x3F, "bgt">; +def BLBC : br_icc<0x38, "blbc">; +def BLBS : br_icc<0x3C, "blbs">; +def BLE : br_icc<0x3B, "ble">; +def BLT : br_icc<0x3A, "blt">; +def BNE : br_icc<0x3D, "bne">; + +//Branches, float +def FBEQ : br_fcc<0x31, "fbeq">; +def FBGE : br_fcc<0x36, "fbge">; +def FBGT : br_fcc<0x37, "fbgt">; +def FBLE : br_fcc<0x33, "fble">; +def FBLT : br_fcc<0x32, "fblt">; +def FBNE : br_fcc<0x36, "fbne">; +} + +//An ugly trick to get the opcode as an imm I can use +def immBRCond : SDNodeXForm<imm, [{ + switch((uint64_t)N->getZExtValue()) { + default: assert(0 && "Unknown branch type"); + case 0: return getI64Imm(Alpha::BEQ); + case 1: return getI64Imm(Alpha::BNE); + case 2: return getI64Imm(Alpha::BGE); + case 3: return getI64Imm(Alpha::BGT); + case 4: return getI64Imm(Alpha::BLE); + case 5: return getI64Imm(Alpha::BLT); + case 6: return getI64Imm(Alpha::BLBS); + case 7: return getI64Imm(Alpha::BLBC); + case 20: return getI64Imm(Alpha::FBEQ); + case 21: return getI64Imm(Alpha::FBNE); + case 22: return getI64Imm(Alpha::FBGE); + case 23: return getI64Imm(Alpha::FBGT); + case 24: return getI64Imm(Alpha::FBLE); + case 25: return getI64Imm(Alpha::FBLT); + } +}]>; + +//Int cond patterns +def : Pat<(brcond (seteq GPRC:$RA, 0), bb:$DISP), + (COND_BRANCH_I (immBRCond 0), GPRC:$RA, bb:$DISP)>; +def : Pat<(brcond (setge GPRC:$RA, 0), bb:$DISP), + (COND_BRANCH_I (immBRCond 2), GPRC:$RA, bb:$DISP)>; +def : Pat<(brcond (setgt GPRC:$RA, 0), bb:$DISP), + (COND_BRANCH_I (immBRCond 3), GPRC:$RA, bb:$DISP)>; +def : Pat<(brcond (and GPRC:$RA, 1), bb:$DISP), + (COND_BRANCH_I (immBRCond 6), GPRC:$RA, bb:$DISP)>; +def : Pat<(brcond (setle GPRC:$RA, 0), bb:$DISP), + (COND_BRANCH_I (immBRCond 4), GPRC:$RA, bb:$DISP)>; +def : Pat<(brcond (setlt GPRC:$RA, 0), bb:$DISP), + (COND_BRANCH_I (immBRCond 5), GPRC:$RA, bb:$DISP)>; +def : Pat<(brcond (setne GPRC:$RA, 0), bb:$DISP), + (COND_BRANCH_I (immBRCond 1), GPRC:$RA, bb:$DISP)>; + +def : Pat<(brcond GPRC:$RA, bb:$DISP), + (COND_BRANCH_I (immBRCond 1), GPRC:$RA, bb:$DISP)>; +def : Pat<(brcond (setne GPRC:$RA, GPRC:$RB), bb:$DISP), + (COND_BRANCH_I (immBRCond 0), (CMPEQ GPRC:$RA, GPRC:$RB), bb:$DISP)>; +def : Pat<(brcond (setne GPRC:$RA, immUExt8:$L), bb:$DISP), + (COND_BRANCH_I (immBRCond 0), (CMPEQi GPRC:$RA, immUExt8:$L), bb:$DISP)>; + +//FP cond patterns +def : Pat<(brcond (seteq F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 20), F8RC:$RA, bb:$DISP)>; +def : Pat<(brcond (setne F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), F8RC:$RA, bb:$DISP)>; +def : Pat<(brcond (setge F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 22), F8RC:$RA, bb:$DISP)>; +def : Pat<(brcond (setgt F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 23), F8RC:$RA, bb:$DISP)>; +def : Pat<(brcond (setle F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 24), F8RC:$RA, bb:$DISP)>; +def : Pat<(brcond (setlt F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 25), F8RC:$RA, bb:$DISP)>; + + +def : Pat<(brcond (seteq F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTEQ F8RC:$RA, F8RC:$RB), bb:$DISP)>; +def : Pat<(brcond (setoeq F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTEQ F8RC:$RA, F8RC:$RB), bb:$DISP)>; +def : Pat<(brcond (setueq F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTEQ F8RC:$RA, F8RC:$RB), bb:$DISP)>; + +def : Pat<(brcond (setlt F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLT F8RC:$RA, F8RC:$RB), bb:$DISP)>; +def : Pat<(brcond (setolt F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLT F8RC:$RA, F8RC:$RB), bb:$DISP)>; +def : Pat<(brcond (setult F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLT F8RC:$RA, F8RC:$RB), bb:$DISP)>; + +def : Pat<(brcond (setle F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLE F8RC:$RA, F8RC:$RB), bb:$DISP)>; +def : Pat<(brcond (setole F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLE F8RC:$RA, F8RC:$RB), bb:$DISP)>; +def : Pat<(brcond (setule F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLE F8RC:$RA, F8RC:$RB), bb:$DISP)>; + +def : Pat<(brcond (setgt F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLT F8RC:$RB, F8RC:$RA), bb:$DISP)>; +def : Pat<(brcond (setogt F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLT F8RC:$RB, F8RC:$RA), bb:$DISP)>; +def : Pat<(brcond (setugt F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLT F8RC:$RB, F8RC:$RA), bb:$DISP)>; + +def : Pat<(brcond (setge F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLE F8RC:$RB, F8RC:$RA), bb:$DISP)>; +def : Pat<(brcond (setoge F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLE F8RC:$RB, F8RC:$RA), bb:$DISP)>; +def : Pat<(brcond (setuge F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), (CMPTLE F8RC:$RB, F8RC:$RA), bb:$DISP)>; + +def : Pat<(brcond (setne F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 20), (CMPTEQ F8RC:$RA, F8RC:$RB), bb:$DISP)>; +def : Pat<(brcond (setone F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 20), (CMPTEQ F8RC:$RA, F8RC:$RB), bb:$DISP)>; +def : Pat<(brcond (setune F8RC:$RA, F8RC:$RB), bb:$DISP), + (COND_BRANCH_F (immBRCond 20), (CMPTEQ F8RC:$RA, F8RC:$RB), bb:$DISP)>; + + +def : Pat<(brcond (setoeq F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 20), F8RC:$RA,bb:$DISP)>; +def : Pat<(brcond (setueq F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 20), F8RC:$RA,bb:$DISP)>; + +def : Pat<(brcond (setoge F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 22), F8RC:$RA,bb:$DISP)>; +def : Pat<(brcond (setuge F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 22), F8RC:$RA,bb:$DISP)>; + +def : Pat<(brcond (setogt F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 23), F8RC:$RA,bb:$DISP)>; +def : Pat<(brcond (setugt F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 23), F8RC:$RA,bb:$DISP)>; + +def : Pat<(brcond (setole F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 24), F8RC:$RA,bb:$DISP)>; +def : Pat<(brcond (setule F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 24), F8RC:$RA,bb:$DISP)>; + +def : Pat<(brcond (setolt F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 25), F8RC:$RA,bb:$DISP)>; +def : Pat<(brcond (setult F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 25), F8RC:$RA,bb:$DISP)>; + +def : Pat<(brcond (setone F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), F8RC:$RA,bb:$DISP)>; +def : Pat<(brcond (setune F8RC:$RA, immFPZ), bb:$DISP), + (COND_BRANCH_F (immBRCond 21), F8RC:$RA,bb:$DISP)>; + +//End Branches + +//S_floating : IEEE Single +//T_floating : IEEE Double + +//Unused instructions +//Mnemonic Format Opcode Description +//CALL_PAL Pcd 00 Trap to PALcode +//ECB Mfc 18.E800 Evict cache block +//EXCB Mfc 18.0400 Exception barrier +//FETCH Mfc 18.8000 Prefetch data +//FETCH_M Mfc 18.A000 Prefetch data, modify intent +//LDQ_U Mem 0B Load unaligned quadword +//MB Mfc 18.4000 Memory barrier +//STQ_U Mem 0F Store unaligned quadword +//TRAPB Mfc 18.0000 Trap barrier +//WH64 Mfc 18.F800 Write hint 64 bytes +//WMB Mfc 18.4400 Write memory barrier +//MF_FPCR F-P 17.025 Move from FPCR +//MT_FPCR F-P 17.024 Move to FPCR +//There are in the Multimedia extentions, so let's not use them yet +//def MAXSB8 : OForm<0x1C, 0x3E, "MAXSB8 $RA,$RB,$RC">; //Vector signed byte maximum +//def MAXSW4 : OForm< 0x1C, 0x3F, "MAXSW4 $RA,$RB,$RC">; //Vector signed word maximum +//def MAXUB8 : OForm<0x1C, 0x3C, "MAXUB8 $RA,$RB,$RC">; //Vector unsigned byte maximum +//def MAXUW4 : OForm< 0x1C, 0x3D, "MAXUW4 $RA,$RB,$RC">; //Vector unsigned word maximum +//def MINSB8 : OForm< 0x1C, 0x38, "MINSB8 $RA,$RB,$RC">; //Vector signed byte minimum +//def MINSW4 : OForm< 0x1C, 0x39, "MINSW4 $RA,$RB,$RC">; //Vector signed word minimum +//def MINUB8 : OForm< 0x1C, 0x3A, "MINUB8 $RA,$RB,$RC">; //Vector unsigned byte minimum +//def MINUW4 : OForm< 0x1C, 0x3B, "MINUW4 $RA,$RB,$RC">; //Vector unsigned word minimum +//def PERR : OForm< 0x1C, 0x31, "PERR $RA,$RB,$RC">; //Pixel error +//def PKLB : OForm< 0x1C, 0x37, "PKLB $RA,$RB,$RC">; //Pack longwords to bytes +//def PKWB : OForm<0x1C, 0x36, "PKWB $RA,$RB,$RC">; //Pack words to bytes +//def UNPKBL : OForm< 0x1C, 0x35, "UNPKBL $RA,$RB,$RC">; //Unpack bytes to longwords +//def UNPKBW : OForm< 0x1C, 0x34, "UNPKBW $RA,$RB,$RC">; //Unpack bytes to words +//CVTLQ F-P 17.010 Convert longword to quadword +//CVTQL F-P 17.030 Convert quadword to longword + + +//Constant handling + +def immConst2Part : PatLeaf<(imm), [{ + //true if imm fits in a LDAH LDA pair + int64_t val = (int64_t)N->getZExtValue(); + return (val <= IMM_FULLHIGH && val >= IMM_FULLLOW); +}]>; +def immConst2PartInt : PatLeaf<(imm), [{ + //true if imm fits in a LDAH LDA pair with zeroext + uint64_t uval = N->getZExtValue(); + int32_t val32 = (int32_t)uval; + return ((uval >> 32) == 0 && //empty upper bits + val32 <= IMM_FULLHIGH); +// val32 >= IMM_FULLLOW + IMM_LOW * IMM_MULT); //Always True +}], SExt32>; + +def : Pat<(i64 immConst2Part:$imm), + (LDA (LL16 immConst2Part:$imm), (LDAH (LH16 immConst2Part:$imm), R31))>; + +def : Pat<(i64 immSExt16:$imm), + (LDA immSExt16:$imm, R31)>; + +def : Pat<(i64 immSExt16int:$imm), + (ZAPNOTi (LDA (SExt16 immSExt16int:$imm), R31), 15)>; +def : Pat<(i64 immConst2PartInt:$imm), + (ZAPNOTi (LDA (LL16 (SExt32 immConst2PartInt:$imm)), + (LDAH (LH16 (SExt32 immConst2PartInt:$imm)), R31)), 15)>; + + +//TODO: I want to just define these like this! +//def : Pat<(i64 0), +// (R31)>; +//def : Pat<(f64 0.0), +// (F31)>; +//def : Pat<(f64 -0.0), +// (CPYSNT F31, F31)>; +//def : Pat<(f32 0.0), +// (F31)>; +//def : Pat<(f32 -0.0), +// (CPYSNS F31, F31)>; + +//Misc Patterns: + +def : Pat<(sext_inreg GPRC:$RB, i32), + (ADDLi GPRC:$RB, 0)>; + +def : Pat<(fabs F8RC:$RB), + (CPYST F31, F8RC:$RB)>; +def : Pat<(fabs F4RC:$RB), + (CPYSS F31, F4RC:$RB)>; +def : Pat<(fneg F8RC:$RB), + (CPYSNT F8RC:$RB, F8RC:$RB)>; +def : Pat<(fneg F4RC:$RB), + (CPYSNS F4RC:$RB, F4RC:$RB)>; + +def : Pat<(fcopysign F4RC:$A, (fneg F4RC:$B)), + (CPYSNS F4RC:$B, F4RC:$A)>; +def : Pat<(fcopysign F8RC:$A, (fneg F8RC:$B)), + (CPYSNT F8RC:$B, F8RC:$A)>; +def : Pat<(fcopysign F4RC:$A, (fneg F8RC:$B)), + (CPYSNSt F8RC:$B, F4RC:$A)>; +def : Pat<(fcopysign F8RC:$A, (fneg F4RC:$B)), + (CPYSNTs F4RC:$B, F8RC:$A)>; + +//Yes, signed multiply high is ugly +def : Pat<(mulhs GPRC:$RA, GPRC:$RB), + (SUBQr (UMULHr GPRC:$RA, GPRC:$RB), (ADDQr (CMOVGEr GPRC:$RB, R31, GPRC:$RA), + (CMOVGEr GPRC:$RA, R31, GPRC:$RB)))>; + +//Stupid crazy arithmetic stuff: +let AddedComplexity = 1 in { +def : Pat<(mul GPRC:$RA, 5), (S4ADDQr GPRC:$RA, GPRC:$RA)>; +def : Pat<(mul GPRC:$RA, 9), (S8ADDQr GPRC:$RA, GPRC:$RA)>; +def : Pat<(mul GPRC:$RA, 3), (S4SUBQr GPRC:$RA, GPRC:$RA)>; +def : Pat<(mul GPRC:$RA, 7), (S8SUBQr GPRC:$RA, GPRC:$RA)>; + +//slight tree expansion if we are multiplying near to a power of 2 +//n is above a power of 2 +def : Pat<(mul GPRC:$RA, immRem1:$imm), + (ADDQr (SLr GPRC:$RA, (nearP2X immRem1:$imm)), GPRC:$RA)>; +def : Pat<(mul GPRC:$RA, immRem2:$imm), + (ADDQr (SLr GPRC:$RA, (nearP2X immRem2:$imm)), (ADDQr GPRC:$RA, GPRC:$RA))>; +def : Pat<(mul GPRC:$RA, immRem3:$imm), + (ADDQr (SLr GPRC:$RA, (nearP2X immRem3:$imm)), (S4SUBQr GPRC:$RA, GPRC:$RA))>; +def : Pat<(mul GPRC:$RA, immRem4:$imm), + (S4ADDQr GPRC:$RA, (SLr GPRC:$RA, (nearP2X immRem4:$imm)))>; +def : Pat<(mul GPRC:$RA, immRem5:$imm), + (ADDQr (SLr GPRC:$RA, (nearP2X immRem5:$imm)), (S4ADDQr GPRC:$RA, GPRC:$RA))>; +def : Pat<(mul GPRC:$RA, immRemP2:$imm), + (ADDQr (SLr GPRC:$RA, (nearP2X immRemP2:$imm)), (SLi GPRC:$RA, (nearP2RemX immRemP2:$imm)))>; + +//n is below a power of 2 +//FIXME: figure out why something is truncating the imm to 32bits +// this will fix 2007-11-27-mulneg3 +//def : Pat<(mul GPRC:$RA, immRem1n:$imm), +// (SUBQr (SLr GPRC:$RA, (nearP2X immRem1n:$imm)), GPRC:$RA)>; +//def : Pat<(mul GPRC:$RA, immRem2n:$imm), +// (SUBQr (SLr GPRC:$RA, (nearP2X immRem2n:$imm)), (ADDQr GPRC:$RA, GPRC:$RA))>; +//def : Pat<(mul GPRC:$RA, immRem3n:$imm), +// (SUBQr (SLr GPRC:$RA, (nearP2X immRem3n:$imm)), (S4SUBQr GPRC:$RA, GPRC:$RA))>; +//def : Pat<(mul GPRC:$RA, immRem4n:$imm), +// (SUBQr (SLr GPRC:$RA, (nearP2X immRem4n:$imm)), (SLi GPRC:$RA, 2))>; +//def : Pat<(mul GPRC:$RA, immRem5n:$imm), +// (SUBQr (SLr GPRC:$RA, (nearP2X immRem5n:$imm)), (S4ADDQr GPRC:$RA, GPRC:$RA))>; +//def : Pat<(mul GPRC:$RA, immRemP2n:$imm), +// (SUBQr (SLr GPRC:$RA, (nearP2X immRemP2n:$imm)), (SLi GPRC:$RA, (nearP2RemX immRemP2n:$imm)))>; +} //Added complexity diff --git a/lib/Target/Alpha/AlphaJITInfo.cpp b/lib/Target/Alpha/AlphaJITInfo.cpp new file mode 100644 index 000000000000..3fecb19d73b7 --- /dev/null +++ b/lib/Target/Alpha/AlphaJITInfo.cpp @@ -0,0 +1,307 @@ +//===-- AlphaJITInfo.cpp - Implement the JIT interfaces for the Alpha ---===// +// +// 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 JIT interfaces for the Alpha target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "jit" +#include "AlphaJITInfo.h" +#include "AlphaRelocations.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/JITCodeEmitter.h" +#include "llvm/Config/alloca.h" +#include "llvm/Support/Debug.h" +#include <cstdlib> +#include <map> +using namespace llvm; + +#define BUILD_OFormatI(Op, RA, LIT, FUN, RC) \ + ((Op << 26) | (RA << 21) | (LIT << 13) | (1 << 12) | (FUN << 5) | (RC)) +#define BUILD_OFormat(Op, RA, RB, FUN, RC) \ + ((Op << 26) | (RA << 21) | (RB << 16) | (FUN << 5) | (RC)) + +#define BUILD_LDA(RD, RS, IMM16) \ + ((0x08 << 26) | ((RD) << 21) | ((RS) << 16) | ((IMM16) & 65535)) +#define BUILD_LDAH(RD, RS, IMM16) \ + ((0x09 << 26) | ((RD) << 21) | ((RS) << 16) | ((IMM16) & 65535)) + +#define BUILD_LDQ(RD, RS, IMM16) \ + ((0x29 << 26) | ((RD) << 21) | ((RS) << 16) | ((IMM16) & 0xFFFF)) + +#define BUILD_JMP(RD, RS, IMM16) \ + ((0x1A << 26) | ((RD) << 21) | ((RS) << 16) | (0x00 << 14) | ((IMM16) & 0x3FFF)) +#define BUILD_JSR(RD, RS, IMM16) \ + ((0x1A << 26) | ((RD) << 21) | ((RS) << 16) | (0x01 << 14) | ((IMM16) & 0x3FFF)) + +#define BUILD_SLLi(RD, RS, IMM8) \ + (BUILD_OFormatI(0x12, RS, IMM8, 0x39, RD)) + +#define BUILD_ORi(RD, RS, IMM8) \ + (BUILD_OFormatI(0x11, RS, IMM8, 0x20, RD)) + +#define BUILD_OR(RD, RS, RT) \ + (BUILD_OFormat(0x11, RS, RT, 0x20, RD)) + + + +static void EmitBranchToAt(void *At, void *To) { + unsigned long Fn = (unsigned long)To; + + unsigned *AtI = (unsigned*)At; + + AtI[0] = BUILD_OR(0, 27, 27); + + DOUT << "Stub targeting " << To << "\n"; + + for (int x = 1; x <= 8; ++x) { + AtI[2*x - 1] = BUILD_SLLi(27,27,8); + unsigned d = (Fn >> (64 - 8 * x)) & 0x00FF; + //DOUT << "outputing " << hex << d << dec << "\n"; + AtI[2*x] = BUILD_ORi(27, 27, d); + } + AtI[17] = BUILD_JMP(31,27,0); //jump, preserving ra, and setting pv + AtI[18] = 0x00FFFFFF; //mark this as a stub +} + +void AlphaJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { + //FIXME + assert(0); +} + +static TargetJITInfo::JITCompilerFn JITCompilerFunction; +//static AlphaJITInfo* AlphaJTI; + +extern "C" { +#ifdef __alpha + + void AlphaCompilationCallbackC(long* oldpv, void* CameFromStub) + { + void* Target = JITCompilerFunction(CameFromStub); + + //rewrite the stub to an unconditional branch + if (((unsigned*)CameFromStub)[18] == 0x00FFFFFF) { + DOUT << "Came from a stub, rewriting\n"; + EmitBranchToAt(CameFromStub, Target); + } else { + DOUT << "confused, didn't come from stub at " << CameFromStub + << " old jump vector " << oldpv + << " new jump vector " << Target << "\n"; + } + + //Change pv to new Target + *oldpv = (long)Target; + } + + void AlphaCompilationCallback(void); + + asm( + ".text\n" + ".globl AlphaComilationCallbackC\n" + ".align 4\n" + ".globl AlphaCompilationCallback\n" + ".ent AlphaCompilationCallback\n" +"AlphaCompilationCallback:\n" + // //get JIT's GOT + "ldgp $29, 0($27)\n" + //Save args, callee saved, and perhaps others? + //args: $16-$21 $f16-$f21 (12) + //callee: $9-$14 $f2-$f9 (14) + //others: fp:$15 ra:$26 pv:$27 (3) + "lda $30, -232($30)\n" + "stq $16, 0($30)\n" + "stq $17, 8($30)\n" + "stq $18, 16($30)\n" + "stq $19, 24($30)\n" + "stq $20, 32($30)\n" + "stq $21, 40($30)\n" + "stt $f16, 48($30)\n" + "stt $f17, 56($30)\n" + "stt $f18, 64($30)\n" + "stt $f19, 72($30)\n" + "stt $f20, 80($30)\n" + "stt $f21, 88($30)\n" + "stq $9, 96($30)\n" + "stq $10, 104($30)\n" + "stq $11, 112($30)\n" + "stq $12, 120($30)\n" + "stq $13, 128($30)\n" + "stq $14, 136($30)\n" + "stt $f2, 144($30)\n" + "stt $f3, 152($30)\n" + "stt $f4, 160($30)\n" + "stt $f5, 168($30)\n" + "stt $f6, 176($30)\n" + "stt $f7, 184($30)\n" + "stt $f8, 192($30)\n" + "stt $f9, 200($30)\n" + "stq $15, 208($30)\n" + "stq $26, 216($30)\n" + "stq $27, 224($30)\n" + + "addq $30, 224, $16\n" //pass the addr of saved pv as the first arg + "bis $0, $0, $17\n" //pass the roughly stub addr in second arg + "jsr $26, AlphaCompilationCallbackC\n" //call without saving ra + + "ldq $16, 0($30)\n" + "ldq $17, 8($30)\n" + "ldq $18, 16($30)\n" + "ldq $19, 24($30)\n" + "ldq $20, 32($30)\n" + "ldq $21, 40($30)\n" + "ldt $f16, 48($30)\n" + "ldt $f17, 56($30)\n" + "ldt $f18, 64($30)\n" + "ldt $f19, 72($30)\n" + "ldt $f20, 80($30)\n" + "ldt $f21, 88($30)\n" + "ldq $9, 96($30)\n" + "ldq $10, 104($30)\n" + "ldq $11, 112($30)\n" + "ldq $12, 120($30)\n" + "ldq $13, 128($30)\n" + "ldq $14, 136($30)\n" + "ldt $f2, 144($30)\n" + "ldt $f3, 152($30)\n" + "ldt $f4, 160($30)\n" + "ldt $f5, 168($30)\n" + "ldt $f6, 176($30)\n" + "ldt $f7, 184($30)\n" + "ldt $f8, 192($30)\n" + "ldt $f9, 200($30)\n" + "ldq $15, 208($30)\n" + "ldq $26, 216($30)\n" + "ldq $27, 224($30)\n" //this was updated in the callback with the target + + "lda $30, 232($30)\n" //restore sp + "jmp $31, ($27)\n" //jump to the new function + ".end AlphaCompilationCallback\n" + ); +#else + void AlphaCompilationCallback() { + cerr << "Cannot call AlphaCompilationCallback() on a non-Alpha arch!\n"; + abort(); + } +#endif +} + +void *AlphaJITInfo::emitFunctionStub(const Function* F, void *Fn, + JITCodeEmitter &JCE) { + //assert(Fn == AlphaCompilationCallback && "Where are you going?\n"); + //Do things in a stupid slow way! + JCE.startGVStub(F, 19*4); + void* Addr = (void*)(intptr_t)JCE.getCurrentPCValue(); + for (int x = 0; x < 19; ++ x) + JCE.emitWordLE(0); + EmitBranchToAt(Addr, Fn); + DOUT << "Emitting Stub to " << Fn << " at [" << Addr << "]\n"; + return JCE.finishGVStub(F); +} + +TargetJITInfo::LazyResolverFn +AlphaJITInfo::getLazyResolverFunction(JITCompilerFn F) { + JITCompilerFunction = F; + // setZerothGOTEntry((void*)AlphaCompilationCallback); + return AlphaCompilationCallback; +} + +//These describe LDAx +static const int IMM_LOW = -32768; +static const int IMM_HIGH = 32767; +static const int IMM_MULT = 65536; + +static long getUpper16(long l) +{ + long y = l / IMM_MULT; + if (l % IMM_MULT > IMM_HIGH) + ++y; + if (l % IMM_MULT < IMM_LOW) + --y; + assert((short)y == y && "displacement out of range"); + return y; +} + +static long getLower16(long l) +{ + long h = getUpper16(l); + long y = l - h * IMM_MULT; + assert(y == (short)y && "Displacement out of range"); + return y; +} + +void AlphaJITInfo::relocate(void *Function, MachineRelocation *MR, + unsigned NumRelocs, unsigned char* GOTBase) { + //because gpdist are paired and relative to the pc of the first inst, + //we need to have some state + + static std::map<std::pair<void*, int>, void*> gpdistmap; + + for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { + unsigned *RelocPos = (unsigned*)Function + MR->getMachineCodeOffset()/4; + long idx = 0; + bool doCommon = true; + switch ((Alpha::RelocationType)MR->getRelocationType()) { + default: assert(0 && "Unknown relocation type!"); + case Alpha::reloc_literal: + //This is a LDQl + idx = MR->getGOTIndex(); + DOUT << "Literal relocation to slot " << idx; + idx = (idx - GOToffset) * 8; + DOUT << " offset " << idx << "\n"; + break; + case Alpha::reloc_gprellow: + idx = (unsigned char*)MR->getResultPointer() - &GOTBase[GOToffset * 8]; + idx = getLower16(idx); + DOUT << "gprellow relocation offset " << idx << "\n"; + DOUT << " Pointer is " << (void*)MR->getResultPointer() + << " GOT is " << (void*)&GOTBase[GOToffset * 8] << "\n"; + break; + case Alpha::reloc_gprelhigh: + idx = (unsigned char*)MR->getResultPointer() - &GOTBase[GOToffset * 8]; + idx = getUpper16(idx); + DOUT << "gprelhigh relocation offset " << idx << "\n"; + DOUT << " Pointer is " << (void*)MR->getResultPointer() + << " GOT is " << (void*)&GOTBase[GOToffset * 8] << "\n"; + break; + case Alpha::reloc_gpdist: + switch (*RelocPos >> 26) { + case 0x09: //LDAH + idx = &GOTBase[GOToffset * 8] - (unsigned char*)RelocPos; + idx = getUpper16(idx); + DOUT << "LDAH: " << idx << "\n"; + //add the relocation to the map + gpdistmap[std::make_pair(Function, MR->getConstantVal())] = RelocPos; + break; + case 0x08: //LDA + assert(gpdistmap[std::make_pair(Function, MR->getConstantVal())] && + "LDAg without seeing LDAHg"); + idx = &GOTBase[GOToffset * 8] - + (unsigned char*)gpdistmap[std::make_pair(Function, MR->getConstantVal())]; + idx = getLower16(idx); + DOUT << "LDA: " << idx << "\n"; + break; + default: + assert(0 && "Cannot handle gpdist yet"); + } + break; + case Alpha::reloc_bsr: { + idx = (((unsigned char*)MR->getResultPointer() - + (unsigned char*)RelocPos) >> 2) + 1; //skip first 2 inst of fun + *RelocPos |= (idx & ((1 << 21)-1)); + doCommon = false; + break; + } + } + if (doCommon) { + short x = (short)idx; + assert(x == idx); + *(short*)RelocPos = x; + } + } +} diff --git a/lib/Target/Alpha/AlphaJITInfo.h b/lib/Target/Alpha/AlphaJITInfo.h new file mode 100644 index 000000000000..edff990dbc24 --- /dev/null +++ b/lib/Target/Alpha/AlphaJITInfo.h @@ -0,0 +1,47 @@ +//===- AlphaJITInfo.h - Alpha impl. of the JIT 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 contains the Alpha implementation of the TargetJITInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef ALPHA_JITINFO_H +#define ALPHA_JITINFO_H + +#include "llvm/Target/TargetJITInfo.h" + +namespace llvm { + class TargetMachine; + + class AlphaJITInfo : public TargetJITInfo { + protected: + TargetMachine &TM; + public: + explicit AlphaJITInfo(TargetMachine &tm) : TM(tm) + { useGOT = true; } + + virtual void *emitFunctionStub(const Function* F, void *Fn, + JITCodeEmitter &JCE); + virtual LazyResolverFn getLazyResolverFunction(JITCompilerFn); + virtual void relocate(void *Function, MachineRelocation *MR, + unsigned NumRelocs, unsigned char* GOTBase); + + /// replaceMachineCodeForFunction - Make it so that calling the function + /// whose machine code is at OLD turns into a call to NEW, perhaps by + /// overwriting OLD with a branch to NEW. This is used for self-modifying + /// code. + /// + virtual void replaceMachineCodeForFunction(void *Old, void *New); + private: + static const unsigned GOToffset = 4096; + + }; +} + +#endif diff --git a/lib/Target/Alpha/AlphaLLRP.cpp b/lib/Target/Alpha/AlphaLLRP.cpp new file mode 100644 index 000000000000..0c51bc554be9 --- /dev/null +++ b/lib/Target/Alpha/AlphaLLRP.cpp @@ -0,0 +1,158 @@ +//===-- AlphaLLRP.cpp - Alpha Load Load Replay Trap elimination pass. -- --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Here we check for potential replay traps introduced by the spiller +// We also align some branch targets if we can do so for free. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "alpha-nops" +#include "Alpha.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/ADT/SetOperations.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/CommandLine.h" +using namespace llvm; + +STATISTIC(nopintro, "Number of nops inserted"); +STATISTIC(nopalign, "Number of nops inserted for alignment"); + +namespace { + cl::opt<bool> + AlignAll("alpha-align-all", cl::Hidden, + cl::desc("Align all blocks")); + + struct AlphaLLRPPass : public MachineFunctionPass { + /// Target machine description which we query for reg. names, data + /// layout, etc. + /// + AlphaTargetMachine &TM; + + static char ID; + AlphaLLRPPass(AlphaTargetMachine &tm) + : MachineFunctionPass(&ID), TM(tm) { } + + virtual const char *getPassName() const { + return "Alpha NOP inserter"; + } + + bool runOnMachineFunction(MachineFunction &F) { + const TargetInstrInfo *TII = F.getTarget().getInstrInfo(); + bool Changed = false; + MachineInstr* prev[3] = {0,0,0}; + DebugLoc dl = DebugLoc::getUnknownLoc(); + unsigned count = 0; + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); + FI != FE; ++FI) { + MachineBasicBlock& MBB = *FI; + bool ub = false; + for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) { + if (count%4 == 0) + prev[0] = prev[1] = prev[2] = 0; //Slots cleared at fetch boundary + ++count; + MachineInstr *MI = I++; + switch (MI->getOpcode()) { + case Alpha::LDQ: case Alpha::LDL: + case Alpha::LDWU: case Alpha::LDBU: + case Alpha::LDT: case Alpha::LDS: + case Alpha::STQ: case Alpha::STL: + case Alpha::STW: case Alpha::STB: + case Alpha::STT: case Alpha::STS: + if (MI->getOperand(2).getReg() == Alpha::R30) { + if (prev[0] && + prev[0]->getOperand(2).getReg() == MI->getOperand(2).getReg()&& + prev[0]->getOperand(1).getImm() == MI->getOperand(1).getImm()){ + prev[0] = prev[1]; + prev[1] = prev[2]; + prev[2] = 0; + BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31) + .addReg(Alpha::R31) + .addReg(Alpha::R31); + Changed = true; nopintro += 1; + count += 1; + } else if (prev[1] + && prev[1]->getOperand(2).getReg() == + MI->getOperand(2).getReg() + && prev[1]->getOperand(1).getImm() == + MI->getOperand(1).getImm()) { + prev[0] = prev[2]; + prev[1] = prev[2] = 0; + BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31) + .addReg(Alpha::R31) + .addReg(Alpha::R31); + BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31) + .addReg(Alpha::R31) + .addReg(Alpha::R31); + Changed = true; nopintro += 2; + count += 2; + } else if (prev[2] + && prev[2]->getOperand(2).getReg() == + MI->getOperand(2).getReg() + && prev[2]->getOperand(1).getImm() == + MI->getOperand(1).getImm()) { + prev[0] = prev[1] = prev[2] = 0; + BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31) + .addReg(Alpha::R31).addReg(Alpha::R31); + BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31) + .addReg(Alpha::R31).addReg(Alpha::R31); + BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31) + .addReg(Alpha::R31).addReg(Alpha::R31); + Changed = true; nopintro += 3; + count += 3; + } + prev[0] = prev[1]; + prev[1] = prev[2]; + prev[2] = MI; + break; + } + prev[0] = prev[1]; + prev[1] = prev[2]; + prev[2] = 0; + break; + case Alpha::ALTENT: + case Alpha::MEMLABEL: + case Alpha::PCLABEL: + --count; + break; + case Alpha::BR: + case Alpha::JMP: + ub = true; + //fall through + default: + prev[0] = prev[1]; + prev[1] = prev[2]; + prev[2] = 0; + break; + } + } + if (ub || AlignAll) { + //we can align stuff for free at this point + while (count % 4) { + BuildMI(MBB, MBB.end(), dl, TII->get(Alpha::BISr), Alpha::R31) + .addReg(Alpha::R31).addReg(Alpha::R31); + ++count; + ++nopalign; + prev[0] = prev[1]; + prev[1] = prev[2]; + prev[2] = 0; + } + } + } + return Changed; + } + }; + char AlphaLLRPPass::ID = 0; +} // end of anonymous namespace + +FunctionPass *llvm::createAlphaLLRPPass(AlphaTargetMachine &tm) { + return new AlphaLLRPPass(tm); +} diff --git a/lib/Target/Alpha/AlphaRegisterInfo.cpp b/lib/Target/Alpha/AlphaRegisterInfo.cpp new file mode 100644 index 000000000000..feee6e467f47 --- /dev/null +++ b/lib/Target/Alpha/AlphaRegisterInfo.cpp @@ -0,0 +1,335 @@ +//===- AlphaRegisterInfo.cpp - Alpha Register 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 Alpha implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "reginfo" +#include "Alpha.h" +#include "AlphaRegisterInfo.h" +#include "llvm/Constants.h" +#include "llvm/Type.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineLocation.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include <cstdlib> +using namespace llvm; + +//These describe LDAx +static const int IMM_LOW = -32768; +static const int IMM_HIGH = 32767; +static const int IMM_MULT = 65536; + +static long getUpper16(long l) +{ + long y = l / IMM_MULT; + if (l % IMM_MULT > IMM_HIGH) + ++y; + return y; +} + +static long getLower16(long l) +{ + long h = getUpper16(l); + return l - h * IMM_MULT; +} + +AlphaRegisterInfo::AlphaRegisterInfo(const TargetInstrInfo &tii) + : AlphaGenRegisterInfo(Alpha::ADJUSTSTACKDOWN, Alpha::ADJUSTSTACKUP), + TII(tii) +{ +} + +const unsigned* AlphaRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) + const { + static const unsigned CalleeSavedRegs[] = { + Alpha::R9, Alpha::R10, + Alpha::R11, Alpha::R12, + Alpha::R13, Alpha::R14, + Alpha::F2, Alpha::F3, + Alpha::F4, Alpha::F5, + Alpha::F6, Alpha::F7, + Alpha::F8, Alpha::F9, 0 + }; + return CalleeSavedRegs; +} + +const TargetRegisterClass* const* +AlphaRegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const { + static const TargetRegisterClass * const CalleeSavedRegClasses[] = { + &Alpha::GPRCRegClass, &Alpha::GPRCRegClass, + &Alpha::GPRCRegClass, &Alpha::GPRCRegClass, + &Alpha::GPRCRegClass, &Alpha::GPRCRegClass, + &Alpha::F8RCRegClass, &Alpha::F8RCRegClass, + &Alpha::F8RCRegClass, &Alpha::F8RCRegClass, + &Alpha::F8RCRegClass, &Alpha::F8RCRegClass, + &Alpha::F8RCRegClass, &Alpha::F8RCRegClass, 0 + }; + return CalleeSavedRegClasses; +} + +BitVector AlphaRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + Reserved.set(Alpha::R15); + Reserved.set(Alpha::R30); + Reserved.set(Alpha::R31); + return Reserved; +} + +//===----------------------------------------------------------------------===// +// Stack Frame Processing methods +//===----------------------------------------------------------------------===// + +// hasFP - Return true if the specified function should have a dedicated frame +// pointer register. This is true if the function has variable sized allocas or +// if frame pointer elimination is disabled. +// +bool AlphaRegisterInfo::hasFP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + return MFI->hasVarSizedObjects(); +} + +void AlphaRegisterInfo:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + if (hasFP(MF)) { + // If we have a frame pointer, turn the adjcallstackup instruction into a + // 'sub ESP, <amt>' and the adjcallstackdown instruction into 'add ESP, + // <amt>' + MachineInstr *Old = I; + uint64_t Amount = Old->getOperand(0).getImm(); + if (Amount != 0) { + // We need to keep the stack aligned properly. To do this, we round the + // amount of space needed for the outgoing arguments up to the next + // alignment boundary. + unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment(); + Amount = (Amount+Align-1)/Align*Align; + + MachineInstr *New; + if (Old->getOpcode() == Alpha::ADJUSTSTACKDOWN) { + New=BuildMI(MF, Old->getDebugLoc(), TII.get(Alpha::LDA), Alpha::R30) + .addImm(-Amount).addReg(Alpha::R30); + } else { + assert(Old->getOpcode() == Alpha::ADJUSTSTACKUP); + New=BuildMI(MF, Old->getDebugLoc(), TII.get(Alpha::LDA), Alpha::R30) + .addImm(Amount).addReg(Alpha::R30); + } + + // Replace the pseudo instruction with a new instruction... + MBB.insert(I, New); + } + } + + MBB.erase(I); +} + +//Alpha has a slightly funny stack: +//Args +//<- incoming SP +//fixed locals (and spills, callee saved, etc) +//<- FP +//variable locals +//<- SP + +void AlphaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS) const { + assert(SPAdj == 0 && "Unexpected"); + + unsigned i = 0; + MachineInstr &MI = *II; + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + bool FP = hasFP(MF); + + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); + } + + int FrameIndex = MI.getOperand(i).getIndex(); + + // Add the base register of R30 (SP) or R15 (FP). + MI.getOperand(i + 1).ChangeToRegister(FP ? Alpha::R15 : Alpha::R30, false); + + // Now add the frame object offset to the offset from the virtual frame index. + int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + + DOUT << "FI: " << FrameIndex << " Offset: " << Offset << "\n"; + + Offset += MF.getFrameInfo()->getStackSize(); + + DOUT << "Corrected Offset " << Offset + << " for stack size: " << MF.getFrameInfo()->getStackSize() << "\n"; + + if (Offset > IMM_HIGH || Offset < IMM_LOW) { + DOUT << "Unconditionally using R28 for evil purposes Offset: " + << Offset << "\n"; + //so in this case, we need to use a temporary register, and move the + //original inst off the SP/FP + //fix up the old: + MI.getOperand(i + 1).ChangeToRegister(Alpha::R28, false); + MI.getOperand(i).ChangeToImmediate(getLower16(Offset)); + //insert the new + MachineInstr* nMI=BuildMI(MF, MI.getDebugLoc(), + TII.get(Alpha::LDAH), Alpha::R28) + .addImm(getUpper16(Offset)).addReg(FP ? Alpha::R15 : Alpha::R30); + MBB.insert(II, nMI); + } else { + MI.getOperand(i).ChangeToImmediate(Offset); + } +} + + +void AlphaRegisterInfo::emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB + MachineBasicBlock::iterator MBBI = MBB.begin(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + DebugLoc dl = (MBBI != MBB.end() ? + MBBI->getDebugLoc() : DebugLoc::getUnknownLoc()); + bool FP = hasFP(MF); + + static int curgpdist = 0; + + //handle GOP offset + BuildMI(MBB, MBBI, dl, TII.get(Alpha::LDAHg), Alpha::R29) + .addGlobalAddress(const_cast<Function*>(MF.getFunction())) + .addReg(Alpha::R27).addImm(++curgpdist); + BuildMI(MBB, MBBI, dl, TII.get(Alpha::LDAg), Alpha::R29) + .addGlobalAddress(const_cast<Function*>(MF.getFunction())) + .addReg(Alpha::R29).addImm(curgpdist); + + //evil const_cast until MO stuff setup to handle const + BuildMI(MBB, MBBI, dl, TII.get(Alpha::ALTENT)) + .addGlobalAddress(const_cast<Function*>(MF.getFunction())); + + // Get the number of bytes to allocate from the FrameInfo + long NumBytes = MFI->getStackSize(); + + if (FP) + NumBytes += 8; //reserve space for the old FP + + // Do we need to allocate space on the stack? + if (NumBytes == 0) return; + + unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment(); + NumBytes = (NumBytes+Align-1)/Align*Align; + + // Update frame info to pretend that this is part of the stack... + MFI->setStackSize(NumBytes); + + // adjust stack pointer: r30 -= numbytes + NumBytes = -NumBytes; + if (NumBytes >= IMM_LOW) { + BuildMI(MBB, MBBI, dl, TII.get(Alpha::LDA), Alpha::R30).addImm(NumBytes) + .addReg(Alpha::R30); + } else if (getUpper16(NumBytes) >= IMM_LOW) { + BuildMI(MBB, MBBI, dl, TII.get(Alpha::LDAH), Alpha::R30) + .addImm(getUpper16(NumBytes)).addReg(Alpha::R30); + BuildMI(MBB, MBBI, dl, TII.get(Alpha::LDA), Alpha::R30) + .addImm(getLower16(NumBytes)).addReg(Alpha::R30); + } else { + cerr << "Too big a stack frame at " << NumBytes << "\n"; + abort(); + } + + //now if we need to, save the old FP and set the new + if (FP) + { + BuildMI(MBB, MBBI, dl, TII.get(Alpha::STQ)) + .addReg(Alpha::R15).addImm(0).addReg(Alpha::R30); + //this must be the last instr in the prolog + BuildMI(MBB, MBBI, dl, TII.get(Alpha::BISr), Alpha::R15) + .addReg(Alpha::R30).addReg(Alpha::R30); + } + +} + +void AlphaRegisterInfo::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + MachineBasicBlock::iterator MBBI = prior(MBB.end()); + assert((MBBI->getOpcode() == Alpha::RETDAG || + MBBI->getOpcode() == Alpha::RETDAGp) + && "Can only insert epilog into returning blocks"); + DebugLoc dl = MBBI->getDebugLoc(); + + bool FP = hasFP(MF); + + // Get the number of bytes allocated from the FrameInfo... + long NumBytes = MFI->getStackSize(); + + //now if we need to, restore the old FP + if (FP) { + //copy the FP into the SP (discards allocas) + BuildMI(MBB, MBBI, dl, TII.get(Alpha::BISr), Alpha::R30).addReg(Alpha::R15) + .addReg(Alpha::R15); + //restore the FP + BuildMI(MBB, MBBI, dl, TII.get(Alpha::LDQ), Alpha::R15) + .addImm(0).addReg(Alpha::R15); + } + + if (NumBytes != 0) { + if (NumBytes <= IMM_HIGH) { + BuildMI(MBB, MBBI, dl, TII.get(Alpha::LDA), Alpha::R30).addImm(NumBytes) + .addReg(Alpha::R30); + } else if (getUpper16(NumBytes) <= IMM_HIGH) { + BuildMI(MBB, MBBI, dl, TII.get(Alpha::LDAH), Alpha::R30) + .addImm(getUpper16(NumBytes)).addReg(Alpha::R30); + BuildMI(MBB, MBBI, dl, TII.get(Alpha::LDA), Alpha::R30) + .addImm(getLower16(NumBytes)).addReg(Alpha::R30); + } else { + cerr << "Too big a stack frame at " << NumBytes << "\n"; + abort(); + } + } +} + +unsigned AlphaRegisterInfo::getRARegister() const { + assert(0 && "What is the return address register"); + return 0; +} + +unsigned AlphaRegisterInfo::getFrameRegister(MachineFunction &MF) const { + return hasFP(MF) ? Alpha::R15 : Alpha::R30; +} + +unsigned AlphaRegisterInfo::getEHExceptionRegister() const { + assert(0 && "What is the exception register"); + return 0; +} + +unsigned AlphaRegisterInfo::getEHHandlerRegister() const { + assert(0 && "What is the exception handler register"); + return 0; +} + +int AlphaRegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const { + assert(0 && "What is the dwarf register number"); + return -1; +} + +#include "AlphaGenRegisterInfo.inc" + +std::string AlphaRegisterInfo::getPrettyName(unsigned reg) +{ + std::string s(RegisterDescriptors[reg].Name); + return s; +} diff --git a/lib/Target/Alpha/AlphaRegisterInfo.h b/lib/Target/Alpha/AlphaRegisterInfo.h new file mode 100644 index 000000000000..c4f5f7b421dd --- /dev/null +++ b/lib/Target/Alpha/AlphaRegisterInfo.h @@ -0,0 +1,67 @@ +//===- AlphaRegisterInfo.h - Alpha 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 Alpha implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef ALPHAREGISTERINFO_H +#define ALPHAREGISTERINFO_H + +#include "llvm/Target/TargetRegisterInfo.h" +#include "AlphaGenRegisterInfo.h.inc" + +namespace llvm { + +class TargetInstrInfo; +class Type; + +struct AlphaRegisterInfo : public AlphaGenRegisterInfo { + const TargetInstrInfo &TII; + + AlphaRegisterInfo(const TargetInstrInfo &tii); + + /// Code Generation virtual methods... + const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const; + + const TargetRegisterClass* const* getCalleeSavedRegClasses( + const MachineFunction *MF = 0) const; + + BitVector getReservedRegs(const MachineFunction &MF) const; + + bool hasFP(const MachineFunction &MF) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; + + //void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; + + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + // Debug information queries. + unsigned getRARegister() const; + unsigned getFrameRegister(MachineFunction &MF) const; + + // Exception handling queries. + unsigned getEHExceptionRegister() const; + unsigned getEHHandlerRegister() const; + + int getDwarfRegNum(unsigned RegNum, bool isEH) const; + + static std::string getPrettyName(unsigned reg); +}; + +} // end namespace llvm + +#endif diff --git a/lib/Target/Alpha/AlphaRegisterInfo.td b/lib/Target/Alpha/AlphaRegisterInfo.td new file mode 100644 index 000000000000..35e6804ea6ac --- /dev/null +++ b/lib/Target/Alpha/AlphaRegisterInfo.td @@ -0,0 +1,171 @@ +//===- AlphaRegisterInfo.td - The Alpha Register File ------*- 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 Alpha register set. +// +//===----------------------------------------------------------------------===// + +class AlphaReg<string n> : Register<n> { + field bits<5> Num; + let Namespace = "Alpha"; +} + +// We identify all our registers with a 5-bit ID, for consistency's sake. + +// GPR - One of the 32 32-bit general-purpose registers +class GPR<bits<5> num, string n> : AlphaReg<n> { + let Num = num; +} + +// FPR - One of the 32 64-bit floating-point registers +class FPR<bits<5> num, string n> : AlphaReg<n> { + let Num = num; +} + +//#define FP $15 +//#define RA $26 +//#define PV $27 +//#define GP $29 +//#define SP $30 + +// General-purpose registers +def R0 : GPR< 0, "$0">, DwarfRegNum<[0]>; +def R1 : GPR< 1, "$1">, DwarfRegNum<[1]>; +def R2 : GPR< 2, "$2">, DwarfRegNum<[2]>; +def R3 : GPR< 3, "$3">, DwarfRegNum<[3]>; +def R4 : GPR< 4, "$4">, DwarfRegNum<[4]>; +def R5 : GPR< 5, "$5">, DwarfRegNum<[5]>; +def R6 : GPR< 6, "$6">, DwarfRegNum<[6]>; +def R7 : GPR< 7, "$7">, DwarfRegNum<[7]>; +def R8 : GPR< 8, "$8">, DwarfRegNum<[8]>; +def R9 : GPR< 9, "$9">, DwarfRegNum<[9]>; +def R10 : GPR<10, "$10">, DwarfRegNum<[10]>; +def R11 : GPR<11, "$11">, DwarfRegNum<[11]>; +def R12 : GPR<12, "$12">, DwarfRegNum<[12]>; +def R13 : GPR<13, "$13">, DwarfRegNum<[13]>; +def R14 : GPR<14, "$14">, DwarfRegNum<[14]>; +def R15 : GPR<15, "$15">, DwarfRegNum<[15]>; +def R16 : GPR<16, "$16">, DwarfRegNum<[16]>; +def R17 : GPR<17, "$17">, DwarfRegNum<[17]>; +def R18 : GPR<18, "$18">, DwarfRegNum<[18]>; +def R19 : GPR<19, "$19">, DwarfRegNum<[19]>; +def R20 : GPR<20, "$20">, DwarfRegNum<[20]>; +def R21 : GPR<21, "$21">, DwarfRegNum<[21]>; +def R22 : GPR<22, "$22">, DwarfRegNum<[22]>; +def R23 : GPR<23, "$23">, DwarfRegNum<[23]>; +def R24 : GPR<24, "$24">, DwarfRegNum<[24]>; +def R25 : GPR<25, "$25">, DwarfRegNum<[25]>; +def R26 : GPR<26, "$26">, DwarfRegNum<[26]>; +def R27 : GPR<27, "$27">, DwarfRegNum<[27]>; +def R28 : GPR<28, "$28">, DwarfRegNum<[28]>; +def R29 : GPR<29, "$29">, DwarfRegNum<[29]>; +def R30 : GPR<30, "$30">, DwarfRegNum<[30]>; +def R31 : GPR<31, "$31">, DwarfRegNum<[31]>; + +// Floating-point registers +def F0 : FPR< 0, "$f0">, DwarfRegNum<[33]>; +def F1 : FPR< 1, "$f1">, DwarfRegNum<[34]>; +def F2 : FPR< 2, "$f2">, DwarfRegNum<[35]>; +def F3 : FPR< 3, "$f3">, DwarfRegNum<[36]>; +def F4 : FPR< 4, "$f4">, DwarfRegNum<[37]>; +def F5 : FPR< 5, "$f5">, DwarfRegNum<[38]>; +def F6 : FPR< 6, "$f6">, DwarfRegNum<[39]>; +def F7 : FPR< 7, "$f7">, DwarfRegNum<[40]>; +def F8 : FPR< 8, "$f8">, DwarfRegNum<[41]>; +def F9 : FPR< 9, "$f9">, DwarfRegNum<[42]>; +def F10 : FPR<10, "$f10">, DwarfRegNum<[43]>; +def F11 : FPR<11, "$f11">, DwarfRegNum<[44]>; +def F12 : FPR<12, "$f12">, DwarfRegNum<[45]>; +def F13 : FPR<13, "$f13">, DwarfRegNum<[46]>; +def F14 : FPR<14, "$f14">, DwarfRegNum<[47]>; +def F15 : FPR<15, "$f15">, DwarfRegNum<[48]>; +def F16 : FPR<16, "$f16">, DwarfRegNum<[49]>; +def F17 : FPR<17, "$f17">, DwarfRegNum<[50]>; +def F18 : FPR<18, "$f18">, DwarfRegNum<[51]>; +def F19 : FPR<19, "$f19">, DwarfRegNum<[52]>; +def F20 : FPR<20, "$f20">, DwarfRegNum<[53]>; +def F21 : FPR<21, "$f21">, DwarfRegNum<[54]>; +def F22 : FPR<22, "$f22">, DwarfRegNum<[55]>; +def F23 : FPR<23, "$f23">, DwarfRegNum<[56]>; +def F24 : FPR<24, "$f24">, DwarfRegNum<[57]>; +def F25 : FPR<25, "$f25">, DwarfRegNum<[58]>; +def F26 : FPR<26, "$f26">, DwarfRegNum<[59]>; +def F27 : FPR<27, "$f27">, DwarfRegNum<[60]>; +def F28 : FPR<28, "$f28">, DwarfRegNum<[61]>; +def F29 : FPR<29, "$f29">, DwarfRegNum<[62]>; +def F30 : FPR<30, "$f30">, DwarfRegNum<[63]>; +def F31 : FPR<31, "$f31">, DwarfRegNum<[64]>; + + // //#define FP $15 + // //#define RA $26 + // //#define PV $27 + // //#define GP $29 + // //#define SP $30 + // $28 is undefined after any and all calls + +/// Register classes +def GPRC : RegisterClass<"Alpha", [i64], 64, + // Volatile + [R0, R1, R2, R3, R4, R5, R6, R7, R8, R16, R17, R18, R19, R20, R21, R22, + R23, R24, R25, R28, + //Special meaning, but volatile + R27, //procedure address + R26, //return address + R29, //global offset table address + // Non-volatile + R9, R10, R11, R12, R13, R14, +// Don't allocate 15, 30, 31 + R15, R30, R31 ]> //zero +{ + let MethodProtos = [{ + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + GPRCClass::iterator + GPRCClass::allocation_order_end(const MachineFunction &MF) const { + return end()-3; + } + }]; +} + +def F4RC : RegisterClass<"Alpha", [f32], 64, [F0, F1, + F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, + F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, + // Saved: + F2, F3, F4, F5, F6, F7, F8, F9, + F31 ]> //zero +{ + let MethodProtos = [{ + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + F4RCClass::iterator + F4RCClass::allocation_order_end(const MachineFunction &MF) const { + return end()-1; + } + }]; +} + +def F8RC : RegisterClass<"Alpha", [f64], 64, [F0, F1, + F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, + F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, + // Saved: + F2, F3, F4, F5, F6, F7, F8, F9, + F31 ]> //zero +{ + let MethodProtos = [{ + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + F8RCClass::iterator + F8RCClass::allocation_order_end(const MachineFunction &MF) const { + return end()-1; + } + }]; +} diff --git a/lib/Target/Alpha/AlphaRelocations.h b/lib/Target/Alpha/AlphaRelocations.h new file mode 100644 index 000000000000..4c92045d4696 --- /dev/null +++ b/lib/Target/Alpha/AlphaRelocations.h @@ -0,0 +1,31 @@ +//===- AlphaRelocations.h - Alpha Code Relocations --------------*- 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 Alpha target-specific relocation types. +// +//===----------------------------------------------------------------------===// + +#ifndef ALPHARELOCATIONS_H +#define ALPHARELOCATIONS_H + +#include "llvm/CodeGen/MachineRelocation.h" + +namespace llvm { + namespace Alpha { + enum RelocationType { + reloc_literal, + reloc_gprellow, + reloc_gprelhigh, + reloc_gpdist, + reloc_bsr + }; + } +} + +#endif diff --git a/lib/Target/Alpha/AlphaSchedule.td b/lib/Target/Alpha/AlphaSchedule.td new file mode 100644 index 000000000000..b7b456084709 --- /dev/null +++ b/lib/Target/Alpha/AlphaSchedule.td @@ -0,0 +1,84 @@ +//===- AlphaSchedule.td - Alpha Scheduling Definitions -----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//This is table 2-2 from the 21264 compiler writers guide +//modified some + +//Pipelines + +def L0 : FuncUnit; +def L1 : FuncUnit; +def FST0 : FuncUnit; +def FST1 : FuncUnit; +def U0 : FuncUnit; +def U1 : FuncUnit; +def FA : FuncUnit; +def FM : FuncUnit; + +def s_ild : InstrItinClass; +def s_fld : InstrItinClass; +def s_ist : InstrItinClass; +def s_fst : InstrItinClass; +def s_lda : InstrItinClass; +def s_rpcc : InstrItinClass; +def s_rx : InstrItinClass; +def s_mxpr : InstrItinClass; +def s_icbr : InstrItinClass; +def s_ubr : InstrItinClass; +def s_jsr : InstrItinClass; +def s_iadd : InstrItinClass; +def s_ilog : InstrItinClass; +def s_ishf : InstrItinClass; +def s_cmov : InstrItinClass; +def s_imul : InstrItinClass; +def s_imisc : InstrItinClass; +def s_fbr : InstrItinClass; +def s_fadd : InstrItinClass; +def s_fmul : InstrItinClass; +def s_fcmov : InstrItinClass; +def s_fdivt : InstrItinClass; +def s_fdivs : InstrItinClass; +def s_fsqrts: InstrItinClass; +def s_fsqrtt: InstrItinClass; +def s_ftoi : InstrItinClass; +def s_itof : InstrItinClass; +def s_pseudo : InstrItinClass; + +//Table 24 Instruction Class Latency in Cycles +//modified some + +def Alpha21264Itineraries : ProcessorItineraries<[ + InstrItinData<s_ild , [InstrStage<3, [L0, L1]>]>, + InstrItinData<s_fld , [InstrStage<4, [L0, L1]>]>, + InstrItinData<s_ist , [InstrStage<0, [L0, L1]>]>, + InstrItinData<s_fst , [InstrStage<0, [FST0, FST1, L0, L1]>]>, + InstrItinData<s_lda , [InstrStage<1, [L0, L1, U0, U1]>]>, + InstrItinData<s_rpcc , [InstrStage<1, [L1]>]>, + InstrItinData<s_rx , [InstrStage<1, [L1]>]>, + InstrItinData<s_mxpr , [InstrStage<1, [L0, L1]>]>, + InstrItinData<s_icbr , [InstrStage<0, [U0, U1]>]>, + InstrItinData<s_ubr , [InstrStage<3, [U0, U1]>]>, + InstrItinData<s_jsr , [InstrStage<3, [L0]>]>, + InstrItinData<s_iadd , [InstrStage<1, [L0, U0, L1, U1]>]>, + InstrItinData<s_ilog , [InstrStage<1, [L0, U0, L1, U1]>]>, + InstrItinData<s_ishf , [InstrStage<1, [U0, U1]>]>, + InstrItinData<s_cmov , [InstrStage<1, [L0, U0, L1, U1]>]>, + InstrItinData<s_imul , [InstrStage<7, [U1]>]>, + InstrItinData<s_imisc , [InstrStage<3, [U0]>]>, + InstrItinData<s_fbr , [InstrStage<0, [FA]>]>, + InstrItinData<s_fadd , [InstrStage<6, [FA]>]>, + InstrItinData<s_fmul , [InstrStage<6, [FM]>]>, + InstrItinData<s_fcmov , [InstrStage<6, [FA]>]>, + InstrItinData<s_fdivs , [InstrStage<12, [FA]>]>, + InstrItinData<s_fdivt , [InstrStage<15, [FA]>]>, + InstrItinData<s_fsqrts , [InstrStage<18, [FA]>]>, + InstrItinData<s_fsqrtt , [InstrStage<33, [FA]>]>, + InstrItinData<s_ftoi , [InstrStage<3, [FST0, FST1, L0, L1]>]>, + InstrItinData<s_itof , [InstrStage<4, [L0, L1]>]> +]>; diff --git a/lib/Target/Alpha/AlphaSubtarget.cpp b/lib/Target/Alpha/AlphaSubtarget.cpp new file mode 100644 index 000000000000..d5a9365d75c1 --- /dev/null +++ b/lib/Target/Alpha/AlphaSubtarget.cpp @@ -0,0 +1,25 @@ +//===- AlphaSubtarget.cpp - Alpha Subtarget 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 implements the Alpha specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#include "AlphaSubtarget.h" +#include "Alpha.h" +#include "AlphaGenSubtarget.inc" +using namespace llvm; + +AlphaSubtarget::AlphaSubtarget(const Module &M, const std::string &FS) + : HasCT(false) { + std::string CPU = "generic"; + + // Parse features string. + ParseSubtargetFeatures(FS, CPU); +} diff --git a/lib/Target/Alpha/AlphaSubtarget.h b/lib/Target/Alpha/AlphaSubtarget.h new file mode 100644 index 000000000000..0a944cb0a634 --- /dev/null +++ b/lib/Target/Alpha/AlphaSubtarget.h @@ -0,0 +1,47 @@ +//=====-- AlphaSubtarget.h - Define Subtarget for the Alpha --*- 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 Alpha specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#ifndef ALPHASUBTARGET_H +#define ALPHASUBTARGET_H + +#include "llvm/Target/TargetInstrItineraries.h" +#include "llvm/Target/TargetSubtarget.h" + +#include <string> + +namespace llvm { +class Module; + +class AlphaSubtarget : public TargetSubtarget { +protected: + + bool HasCT; + + InstrItineraryData InstrItins; + +public: + /// This constructor initializes the data members to match that + /// of the specified module. + /// + AlphaSubtarget(const Module &M, const std::string &FS); + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + std::string ParseSubtargetFeatures(const std::string &FS, + const std::string &CPU); + + bool hasCT() const { return HasCT; } +}; +} // End llvm namespace + +#endif diff --git a/lib/Target/Alpha/AlphaTargetAsmInfo.cpp b/lib/Target/Alpha/AlphaTargetAsmInfo.cpp new file mode 100644 index 000000000000..6092ab67b5fc --- /dev/null +++ b/lib/Target/Alpha/AlphaTargetAsmInfo.cpp @@ -0,0 +1,31 @@ +//===-- AlphaTargetAsmInfo.cpp - Alpha 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 declarations of the AlphaTargetAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "AlphaTargetMachine.h" +#include "AlphaTargetAsmInfo.h" + +using namespace llvm; + +AlphaTargetAsmInfo::AlphaTargetAsmInfo(const AlphaTargetMachine &TM) + : TargetAsmInfo(TM) { + AlignmentIsInBytes = false; + PrivateGlobalPrefix = "$"; + JumpTableDirective = ".gprel32"; + JumpTableDataSection = "\t.section .rodata\n"; + WeakRefDirective = "\t.weak\t"; +} + +unsigned AlphaTargetAsmInfo::RelocBehaviour() const { + return (TM.getRelocationModel() != Reloc::Static ? + Reloc::LocalOrGlobal : Reloc::Global); +} diff --git a/lib/Target/Alpha/AlphaTargetAsmInfo.h b/lib/Target/Alpha/AlphaTargetAsmInfo.h new file mode 100644 index 000000000000..7675b26f6e81 --- /dev/null +++ b/lib/Target/Alpha/AlphaTargetAsmInfo.h @@ -0,0 +1,32 @@ +//=====-- AlphaTargetAsmInfo.h - Alpha 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 AlphaTargetAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef ALPHATARGETASMINFO_H +#define ALPHATARGETASMINFO_H + +#include "llvm/Target/TargetAsmInfo.h" + +namespace llvm { + + // Forward declaration. + class AlphaTargetMachine; + + struct AlphaTargetAsmInfo : public TargetAsmInfo { + explicit AlphaTargetAsmInfo(const AlphaTargetMachine &TM); + + virtual unsigned RelocBehaviour() const; + }; + +} // namespace llvm + +#endif diff --git a/lib/Target/Alpha/AlphaTargetMachine.cpp b/lib/Target/Alpha/AlphaTargetMachine.cpp new file mode 100644 index 000000000000..4c830541f16a --- /dev/null +++ b/lib/Target/Alpha/AlphaTargetMachine.cpp @@ -0,0 +1,126 @@ +//===-- AlphaTargetMachine.cpp - Define TargetMachine for Alpha -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#include "Alpha.h" +#include "AlphaJITInfo.h" +#include "AlphaTargetAsmInfo.h" +#include "AlphaTargetMachine.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Target/TargetMachineRegistry.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +/// AlphaTargetMachineModule - Note that this is used on hosts that cannot link +/// in a library unless there are references into the library. In particular, +/// it seems that it is not possible to get things to work on Win32 without +/// this. Though it is unused, do not remove it. +extern "C" int AlphaTargetMachineModule; +int AlphaTargetMachineModule = 0; + +// Register the targets +static RegisterTarget<AlphaTargetMachine> X("alpha", "Alpha [experimental]"); + +const TargetAsmInfo *AlphaTargetMachine::createTargetAsmInfo() const { + return new AlphaTargetAsmInfo(*this); +} + +unsigned AlphaTargetMachine::getModuleMatchQuality(const Module &M) { + // We strongly match "alpha*". + std::string TT = M.getTargetTriple(); + if (TT.size() >= 5 && TT[0] == 'a' && TT[1] == 'l' && TT[2] == 'p' && + TT[3] == 'h' && TT[4] == 'a') + return 20; + // If the target triple is something non-alpha, we don't match. + if (!TT.empty()) return 0; + + if (M.getEndianness() == Module::LittleEndian && + M.getPointerSize() == Module::Pointer64) + return 10; // Weak match + else if (M.getEndianness() != Module::AnyEndianness || + M.getPointerSize() != Module::AnyPointerSize) + return 0; // Match for some other target + + return getJITMatchQuality()/2; +} + +unsigned AlphaTargetMachine::getJITMatchQuality() { +#ifdef __alpha + return 10; +#else + return 0; +#endif +} + +AlphaTargetMachine::AlphaTargetMachine(const Module &M, const std::string &FS) + : DataLayout("e-f128:128:128"), + FrameInfo(TargetFrameInfo::StackGrowsDown, 16, 0), + JITInfo(*this), + Subtarget(M, FS), + TLInfo(*this) { + setRelocationModel(Reloc::PIC_); +} + + +//===----------------------------------------------------------------------===// +// Pass Pipeline Configuration +//===----------------------------------------------------------------------===// + +bool AlphaTargetMachine::addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + PM.add(createAlphaISelDag(*this)); + return false; +} +bool AlphaTargetMachine::addPreEmitPass(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + // Must run branch selection immediately preceding the asm printer + PM.add(createAlphaBranchSelectionPass()); + return false; +} +bool AlphaTargetMachine::addAssemblyEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool Verbose, + raw_ostream &Out) { + PM.add(createAlphaLLRPPass(*this)); + PM.add(createAlphaCodePrinterPass(Out, *this, OptLevel, Verbose)); + return false; +} +bool AlphaTargetMachine::addCodeEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool DumpAsm, MachineCodeEmitter &MCE) { + PM.add(createAlphaCodeEmitterPass(*this, MCE)); + if (DumpAsm) + PM.add(createAlphaCodePrinterPass(errs(), *this, OptLevel, true)); + return false; +} +bool AlphaTargetMachine::addCodeEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool DumpAsm, JITCodeEmitter &JCE) { + PM.add(createAlphaJITCodeEmitterPass(*this, JCE)); + if (DumpAsm) + PM.add(createAlphaCodePrinterPass(errs(), *this, OptLevel, true)); + return false; +} +bool AlphaTargetMachine::addSimpleCodeEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool DumpAsm, + MachineCodeEmitter &MCE) { + return addCodeEmitter(PM, OptLevel, DumpAsm, MCE); +} +bool AlphaTargetMachine::addSimpleCodeEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool DumpAsm, + JITCodeEmitter &JCE) { + return addCodeEmitter(PM, OptLevel, DumpAsm, JCE); +} + diff --git a/lib/Target/Alpha/AlphaTargetMachine.h b/lib/Target/Alpha/AlphaTargetMachine.h new file mode 100644 index 000000000000..51224e80de70 --- /dev/null +++ b/lib/Target/Alpha/AlphaTargetMachine.h @@ -0,0 +1,82 @@ +//===-- AlphaTargetMachine.h - Define TargetMachine for Alpha ---*- 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 Alpha-specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef ALPHA_TARGETMACHINE_H +#define ALPHA_TARGETMACHINE_H + +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "AlphaInstrInfo.h" +#include "AlphaJITInfo.h" +#include "AlphaISelLowering.h" +#include "AlphaSubtarget.h" + +namespace llvm { + +class GlobalValue; + +class AlphaTargetMachine : public LLVMTargetMachine { + const TargetData DataLayout; // Calculates type size & alignment + AlphaInstrInfo InstrInfo; + TargetFrameInfo FrameInfo; + AlphaJITInfo JITInfo; + AlphaSubtarget Subtarget; + AlphaTargetLowering TLInfo; + +protected: + virtual const TargetAsmInfo *createTargetAsmInfo() const; + +public: + AlphaTargetMachine(const Module &M, const std::string &FS); + + virtual const AlphaInstrInfo *getInstrInfo() const { return &InstrInfo; } + virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; } + virtual const AlphaSubtarget *getSubtargetImpl() const{ return &Subtarget; } + virtual const AlphaRegisterInfo *getRegisterInfo() const { + return &InstrInfo.getRegisterInfo(); + } + virtual AlphaTargetLowering* getTargetLowering() const { + return const_cast<AlphaTargetLowering*>(&TLInfo); + } + virtual const TargetData *getTargetData() const { return &DataLayout; } + virtual AlphaJITInfo* getJITInfo() { + return &JITInfo; + } + + static unsigned getJITMatchQuality(); + static unsigned getModuleMatchQuality(const Module &M); + + // Pass Pipeline Configuration + virtual bool addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel); + virtual bool addPreEmitPass(PassManagerBase &PM, CodeGenOpt::Level OptLevel); + virtual bool addAssemblyEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool Verbose, raw_ostream &Out); + virtual bool addCodeEmitter(PassManagerBase &PM, CodeGenOpt::Level OptLevel, + bool DumpAsm, MachineCodeEmitter &MCE); + virtual bool addCodeEmitter(PassManagerBase &PM, CodeGenOpt::Level OptLevel, + bool DumpAsm, JITCodeEmitter &JCE); + virtual bool addSimpleCodeEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool DumpAsm, + MachineCodeEmitter &MCE); + virtual bool addSimpleCodeEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool DumpAsm, + JITCodeEmitter &JCE); +}; + +} // end namespace llvm + +#endif diff --git a/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp b/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp new file mode 100644 index 000000000000..74b48ee66235 --- /dev/null +++ b/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp @@ -0,0 +1,305 @@ +//===-- AlphaAsmPrinter.cpp - Alpha LLVM assembly writer ------------------===// +// +// 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 Alpha assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "Alpha.h" +#include "AlphaInstrInfo.h" +#include "AlphaTargetMachine.h" +#include "llvm/Module.h" +#include "llvm/Type.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DwarfWriter.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Mangler.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/Statistic.h" +using namespace llvm; + +STATISTIC(EmittedInsts, "Number of machine instrs printed"); + +namespace { + struct VISIBILITY_HIDDEN AlphaAsmPrinter : public AsmPrinter { + /// Unique incrementer for label values for referencing Global values. + /// + + explicit AlphaAsmPrinter(raw_ostream &o, TargetMachine &tm, + const TargetAsmInfo *T, CodeGenOpt::Level OL, + bool V) + : AsmPrinter(o, tm, T, OL, V) {} + + virtual const char *getPassName() const { + return "Alpha Assembly Printer"; + } + bool printInstruction(const MachineInstr *MI); + void printOp(const MachineOperand &MO, bool IsCallOp = false); + void printOperand(const MachineInstr *MI, int opNum); + void printBaseOffsetPair (const MachineInstr *MI, int i, bool brackets=true); + void printModuleLevelGV(const GlobalVariable* GVar); + bool runOnMachineFunction(MachineFunction &F); + bool doInitialization(Module &M); + bool doFinalization(Module &M); + + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode); + bool PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode); + }; +} // end of anonymous namespace + +/// createAlphaCodePrinterPass - Returns a pass that prints the Alpha +/// assembly code for a MachineFunction to the given output stream, +/// using the given target machine description. This should work +/// regardless of whether the function is in SSA form. +/// +FunctionPass *llvm::createAlphaCodePrinterPass(raw_ostream &o, + TargetMachine &tm, + CodeGenOpt::Level OptLevel, + bool verbose) { + return new AlphaAsmPrinter(o, tm, tm.getTargetAsmInfo(), OptLevel, verbose); +} + +#include "AlphaGenAsmWriter.inc" + +void AlphaAsmPrinter::printOperand(const MachineInstr *MI, int opNum) +{ + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.getType() == MachineOperand::MO_Register) { + assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && + "Not physreg??"); + O << TM.getRegisterInfo()->get(MO.getReg()).AsmName; + } else if (MO.isImm()) { + O << MO.getImm(); + assert(MO.getImm() < (1 << 30)); + } else { + printOp(MO); + } +} + + +void AlphaAsmPrinter::printOp(const MachineOperand &MO, bool IsCallOp) { + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << RI.get(MO.getReg()).AsmName; + return; + + case MachineOperand::MO_Immediate: + cerr << "printOp() does not handle immediate values\n"; + abort(); + return; + + case MachineOperand::MO_MachineBasicBlock: + printBasicBlockLabel(MO.getMBB()); + return; + + case MachineOperand::MO_ConstantPoolIndex: + O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" + << MO.getIndex(); + return; + + case MachineOperand::MO_ExternalSymbol: + O << MO.getSymbolName(); + return; + + case MachineOperand::MO_GlobalAddress: { + GlobalValue *GV = MO.getGlobal(); + O << Mang->getValueName(GV); + if (GV->isDeclaration() && GV->hasExternalWeakLinkage()) + ExtWeakSymbols.insert(GV); + return; + } + + case MachineOperand::MO_JumpTableIndex: + O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() + << '_' << MO.getIndex(); + return; + + default: + O << "<unknown operand type: " << MO.getType() << ">"; + return; + } +} + +/// runOnMachineFunction - This uses the printMachineInstruction() +/// method to print assembly for each instruction. +/// +bool AlphaAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + this->MF = &MF; + + SetupMachineFunction(MF); + O << "\n\n"; + + // Print out constants referenced by the function + EmitConstantPool(MF.getConstantPool()); + + // Print out jump tables referenced by the function + EmitJumpTableInfo(MF.getJumpTableInfo(), MF); + + // Print out labels for the function. + const Function *F = MF.getFunction(); + SwitchToSection(TAI->SectionForGlobal(F)); + + EmitAlignment(4, F); + switch (F->getLinkage()) { + default: assert(0 && "Unknown linkage type!"); + case Function::InternalLinkage: // Symbols default to internal. + case Function::PrivateLinkage: + break; + case Function::ExternalLinkage: + O << "\t.globl " << CurrentFnName << "\n"; + break; + case Function::WeakAnyLinkage: + case Function::WeakODRLinkage: + case Function::LinkOnceAnyLinkage: + case Function::LinkOnceODRLinkage: + O << TAI->getWeakRefDirective() << CurrentFnName << "\n"; + break; + } + + printVisibility(CurrentFnName, F->getVisibility()); + + O << "\t.ent " << CurrentFnName << "\n"; + + O << CurrentFnName << ":\n"; + + // Print out code for the function. + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + if (I != MF.begin()) { + printBasicBlockLabel(I, true, true); + O << '\n'; + } + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Print the assembly for the instruction. + ++EmittedInsts; + if (!printInstruction(II)) { + assert(0 && "Unhandled instruction in asm writer!"); + abort(); + } + } + } + + O << "\t.end " << CurrentFnName << "\n"; + + // We didn't modify anything. + return false; +} + +bool AlphaAsmPrinter::doInitialization(Module &M) +{ + if(TM.getSubtarget<AlphaSubtarget>().hasCT()) + O << "\t.arch ev6\n"; //This might need to be ev67, so leave this test here + else + O << "\t.arch ev6\n"; + O << "\t.set noat\n"; + return AsmPrinter::doInitialization(M); +} + +void AlphaAsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) { + const TargetData *TD = TM.getTargetData(); + + if (!GVar->hasInitializer()) return; // External global require no code + + // Check to see if this is a special global used by LLVM, if so, emit it. + if (EmitSpecialLLVMGlobal(GVar)) + return; + + std::string name = Mang->getValueName(GVar); + Constant *C = GVar->getInitializer(); + unsigned Size = TD->getTypeAllocSize(C->getType()); + unsigned Align = TD->getPreferredAlignmentLog(GVar); + + // 0: Switch to section + SwitchToSection(TAI->SectionForGlobal(GVar)); + + // 1: Check visibility + printVisibility(name, GVar->getVisibility()); + + // 2: Kind + switch (GVar->getLinkage()) { + case GlobalValue::LinkOnceAnyLinkage: + case GlobalValue::LinkOnceODRLinkage: + case GlobalValue::WeakAnyLinkage: + case GlobalValue::WeakODRLinkage: + case GlobalValue::CommonLinkage: + O << TAI->getWeakRefDirective() << name << '\n'; + break; + case GlobalValue::AppendingLinkage: + case GlobalValue::ExternalLinkage: + O << TAI->getGlobalDirective() << name << "\n"; + break; + case GlobalValue::InternalLinkage: + case GlobalValue::PrivateLinkage: + break; + default: + assert(0 && "Unknown linkage type!"); + cerr << "Unknown linkage type!\n"; + abort(); + } + + // 3: Type, Size, Align + if (TAI->hasDotTypeDotSizeDirective()) { + O << "\t.type\t" << name << ", @object\n"; + O << "\t.size\t" << name << ", " << Size << "\n"; + } + + EmitAlignment(Align, GVar); + + O << name << ":\n"; + + // If the initializer is a extern weak symbol, remember to emit the weak + // reference! + if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) + if (GV->hasExternalWeakLinkage()) + ExtWeakSymbols.insert(GV); + + EmitGlobalConstant(C); + O << '\n'; +} + +bool AlphaAsmPrinter::doFinalization(Module &M) { + for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) + printModuleLevelGV(I); + + return AsmPrinter::doFinalization(M); +} + +/// PrintAsmOperand - Print out an operand for an inline asm expression. +/// +bool AlphaAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode) { + printOperand(MI, OpNo); + return false; +} + +bool AlphaAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode) { + if (ExtraCode && ExtraCode[0]) + return true; // Unknown modifier. + O << "0("; + printOperand(MI, OpNo); + O << ")"; + return false; +} diff --git a/lib/Target/Alpha/AsmPrinter/CMakeLists.txt b/lib/Target/Alpha/AsmPrinter/CMakeLists.txt new file mode 100644 index 000000000000..b62a7f683568 --- /dev/null +++ b/lib/Target/Alpha/AsmPrinter/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_partially_linked_object(LLVMAlphaAsmPrinter + AlphaAsmPrinter.cpp + ) + +target_name_of_partially_linked_object(LLVMAlphaCodeGen n) + +add_dependencies(LLVMAlphaAsmPrinter ${n}) diff --git a/lib/Target/Alpha/AsmPrinter/Makefile b/lib/Target/Alpha/AsmPrinter/Makefile new file mode 100644 index 000000000000..c5b3e946695b --- /dev/null +++ b/lib/Target/Alpha/AsmPrinter/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/Alpha/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 = LLVMAlphaAsmPrinter + +# Hack: we need to include 'main' alpha target directory to grab private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/Alpha/CMakeLists.txt b/lib/Target/Alpha/CMakeLists.txt new file mode 100644 index 000000000000..1e535f7769a3 --- /dev/null +++ b/lib/Target/Alpha/CMakeLists.txt @@ -0,0 +1,25 @@ +set(LLVM_TARGET_DEFINITIONS Alpha.td) + +tablegen(AlphaGenRegisterInfo.h.inc -gen-register-desc-header) +tablegen(AlphaGenRegisterNames.inc -gen-register-enums) +tablegen(AlphaGenRegisterInfo.inc -gen-register-desc) +tablegen(AlphaGenInstrNames.inc -gen-instr-enums) +tablegen(AlphaGenInstrInfo.inc -gen-instr-desc) +tablegen(AlphaGenCodeEmitter.inc -gen-emitter) +tablegen(AlphaGenAsmWriter.inc -gen-asm-writer) +tablegen(AlphaGenDAGISel.inc -gen-dag-isel) +tablegen(AlphaGenSubtarget.inc -gen-subtarget) + +add_llvm_target(AlphaCodeGen + AlphaBranchSelector.cpp + AlphaCodeEmitter.cpp + AlphaInstrInfo.cpp + AlphaISelDAGToDAG.cpp + AlphaISelLowering.cpp + AlphaJITInfo.cpp + AlphaLLRP.cpp + AlphaRegisterInfo.cpp + AlphaSubtarget.cpp + AlphaTargetAsmInfo.cpp + AlphaTargetMachine.cpp + ) diff --git a/lib/Target/Alpha/Makefile b/lib/Target/Alpha/Makefile new file mode 100644 index 000000000000..d6c82c7d7435 --- /dev/null +++ b/lib/Target/Alpha/Makefile @@ -0,0 +1,22 @@ +##===- lib/Target/Alpha/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 = LLVMAlphaCodeGen +TARGET = Alpha + +# Make sure that tblgen is run, first thing. +BUILT_SOURCES = AlphaGenRegisterInfo.h.inc AlphaGenRegisterNames.inc \ + AlphaGenRegisterInfo.inc AlphaGenInstrNames.inc \ + AlphaGenInstrInfo.inc AlphaGenCodeEmitter.inc \ + AlphaGenAsmWriter.inc AlphaGenDAGISel.inc \ + AlphaGenSubtarget.inc + +DIRS = AsmPrinter + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/Alpha/README.txt b/lib/Target/Alpha/README.txt new file mode 100644 index 000000000000..9ae15174c582 --- /dev/null +++ b/lib/Target/Alpha/README.txt @@ -0,0 +1,42 @@ +*** + +add gcc builtins for alpha instructions + + +*** + +custom expand byteswap into nifty +extract/insert/mask byte/word/longword/quadword low/high +sequences + +*** + +see if any of the extract/insert/mask operations can be added + +*** + +match more interesting things for cmovlbc cmovlbs (move if low bit clear/set) + +*** + +lower srem and urem + +remq(i,j): i - (j * divq(i,j)) if j != 0 +remqu(i,j): i - (j * divqu(i,j)) if j != 0 +reml(i,j): i - (j * divl(i,j)) if j != 0 +remlu(i,j): i - (j * divlu(i,j)) if j != 0 + +*** + +add crazy vector instructions (MVI): + +(MIN|MAX)(U|S)(B8|W4) min and max, signed and unsigned, byte and word +PKWB, UNPKBW pack/unpack word to byte +PKLB UNPKBL pack/unpack long to byte +PERR pixel error (sum accross bytes of bytewise abs(i8v8 a - i8v8 b)) + +cmpbytes bytewise cmpeq of i8v8 a and i8v8 b (not part of MVI extentions) + +this has some good examples for other operations that can be synthesised well +from these rather meager vector ops (such as saturating add). +http://www.alphalinux.org/docs/MVI-full.html |