Index: lib/Target/AAP/AAP.h =================================================================== --- lib/Target/AAP/AAP.h +++ lib/Target/AAP/AAP.h @@ -33,6 +33,12 @@ namespace llvm { +class AAPTargetMachine; +class FunctionPass; + +FunctionPass *createAAPISelDag(AAPTargetMachine &TM, + CodeGenOpt::Level OptLevel); + namespace AAP { // Various helper methods to define operand ranges used throughout the backend static bool inline isImm3(int64_t I) { return isUInt<3>(I); } Index: lib/Target/AAP/AAP.td =================================================================== --- lib/Target/AAP/AAP.td +++ lib/Target/AAP/AAP.td @@ -31,6 +31,7 @@ //===----------------------------------------------------------------------===// include "AAPRegisterInfo.td" +include "AAPCallingConv.td" include "AAPInstrFormats.td" include "AAPInstrInfo.td" Index: lib/Target/AAP/AAPAsmPrinter.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPAsmPrinter.cpp @@ -0,0 +1,119 @@ +//===-- AAPAsmPrinter.cpp - AAP 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 the AAP assembly language. +// +//===----------------------------------------------------------------------===// + +#include "AAPInstrInfo.h" +#include "AAPMCInstLower.h" +#include "InstPrinter/AAPInstPrinter.h" +#include "MCTargetDesc/AAPMCTargetDesc.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +namespace { +class AAPAsmPrinter : public AsmPrinter { +public: + AAPAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) + : AsmPrinter(TM, std::move(Streamer)) {} + + StringRef getPassName() const override { return "AAP Assembly Printer"; } + + void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, + const char *Modifier = nullptr); + + void printMemOffOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, + const char *Modifier = nullptr); + + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O) override; + + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O) override; + + void EmitInstruction(const MachineInstr *MI) override; +}; +} // end of anonymous namespace + +void AAPAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char *Modifier) { + const MachineOperand &MO = MI->getOperand(OpNum); + switch (MO.getType()) { + default: + llvm_unreachable("Not implemented yet!"); + case MachineOperand::MO_Register: + O << '$' << AAPInstPrinter::getRegisterName(MO.getReg()); + return; + case MachineOperand::MO_Immediate: + O << MO.getImm(); + return; + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + case MachineOperand::MO_GlobalAddress: { + O << *getSymbol(MO.getGlobal()); + return; + } + } +} + +void AAPAsmPrinter::printMemOffOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char *Modifier) { + printOperand(MI, OpNum, O); + O << ", "; + printOperand(MI, OpNum + 1, O); +} + +bool AAPAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O) { + printOperand(MI, OpNo, O); + return false; +} + +bool AAPAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + printMemOffOperand(MI, OpNo, O); + return false; +} + +void AAPAsmPrinter::EmitInstruction(const MachineInstr *MI) { + AAPMCInstLower MCInstLowering(OutContext, *this); + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + EmitToStreamer(*OutStreamer, TmpInst); +} + +// Force static initialization. +extern "C" void LLVMInitializeAAPAsmPrinter() { + RegisterAsmPrinter X(getTheAAPTarget()); +} Index: lib/Target/AAP/AAPCallingConv.td =================================================================== --- /dev/null +++ lib/Target/AAP/AAPCallingConv.td @@ -0,0 +1,45 @@ +//===- AAPCallingConv.td - Calling Conventions for AAP -----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This describes the calling conventions for the AAP architectures. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Return Value Calling Conventions +//===----------------------------------------------------------------------===// + +def RetCC_AAP : CallingConv<[ + // Use the same registers for returns as argument passing. + CCIfType<[i16], CCAssignToReg<[R2, R3, R4, R5, R6, R7]>> +]>; + +//===----------------------------------------------------------------------===// +// Argument Calling Conventions +//===----------------------------------------------------------------------===// + +def CC_AAP : CallingConv<[ + // Promote i8 args to i16 + CCIfType<[i8], CCPromoteToType>, + + // All arguments get passed into registers if there is space. + CCIfType<[i16], CCAssignToReg<[R2, R3, R4, R5, R6, R7]>>, + + // Alternatively they are added to the stack. + CCAssignToStack<2, 2> +]>; + +// The callee saved registers are spread out to ensure that approximately +// two-third are callee-saved even when the number of registers is restricted. +// +// R1 is reserved as the stack pointer +def CSR : CalleeSavedRegs<(add R0, R2, R3, R4, R5, R6, R7, R8, R9, R11, R12, + R14, R15, R17, R18, R20, R21, R23, R24, R26, R27, + R29, R30, R32, R34, R36, R38, R40, R42, R44, R46, + R48, R50, R52, R54, R56, R58, R60, R62)>; Index: lib/Target/AAP/AAPFrameLowering.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAPFrameLowering.h @@ -0,0 +1,43 @@ +//===-- AAPFrameLowering.h - Frame info for AAP Target ----------*- 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 AAP implementation of the TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#ifndef AAPFRAMELOWERING_H +#define AAPFRAMELOWERING_H + +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class AAPSubtarget; + +class AAPFrameLowering : public TargetFrameLowering { +public: + AAPFrameLowering(); + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + + MachineBasicBlock::iterator + eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const override; + + bool hasFP(const MachineFunction &MF) const override; + + void processFunctionBeforeFrameFinalized( + MachineFunction &MF, RegScavenger *RS = nullptr) const override; +}; +} + +#endif Index: lib/Target/AAP/AAPFrameLowering.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPFrameLowering.cpp @@ -0,0 +1,132 @@ +//===-- AAPFrameLowering.cpp - Frame info for AAP Target ------------------===// +// +// 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 AAP implementation of the TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "AAPFrameLowering.h" +#include "AAPInstrInfo.h" +#include "AAPMachineFunctionInfo.h" +#include "AAPSubtarget.h" +#include "MCTargetDesc/AAPMCTargetDesc.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetLowering.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// AAPFrameLowering: +//===----------------------------------------------------------------------===// + +AAPFrameLowering::AAPFrameLowering() + : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 2, 0, 2) {} + +bool AAPFrameLowering::hasFP(const MachineFunction &MF) const { + return MF.getTarget().Options.DisableFramePointerElim(MF) || + MF.getFrameInfo().hasVarSizedObjects(); +} + +void AAPFrameLowering::emitPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineFrameInfo &MFrameInfo = MF.getFrameInfo(); + AAPMachineFunctionInfo *MFuncInfo = MF.getInfo(); + const AAPInstrInfo &TII = + *static_cast(MF.getSubtarget().getInstrInfo()); + + auto MBBI = MBB.begin(); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // Get the number of bytes to allocate from the FrameInfo + const uint64_t StackSize = MFrameInfo.getStackSize(); + + assert(!hasFP(MF) && "Frame pointer unsupported!"); + + uint64_t NumBytes = StackSize - MFuncInfo->getCalleeSavedFrameSize(); + const unsigned SP = AAPRegisterInfo::getStackPtrRegister(); + + // Adjust the stack pointer if there is a stack to allocate + if (NumBytes) { + const uint64_t Addend = NumBytes % 1023; + const uint64_t NumChunks = NumBytes / 1023; + + for (uint64_t i = 0; i < NumChunks; ++i) { + BuildMI(MBB, MBBI, DL, TII.get(AAP::SUBI_i10), SP) + .addReg(SP) + .addImm(1023); + } + if (Addend) { + BuildMI(MBB, MBBI, DL, TII.get(AAP::SUBI_i10), SP) + .addReg(SP) + .addImm(Addend); + } + } +} + +void AAPFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + const MachineFrameInfo &MFrameInfo = MF.getFrameInfo(); + AAPMachineFunctionInfo *MFuncInfo = MF.getInfo(); + const AAPInstrInfo &TII = + *static_cast(MF.getSubtarget().getInstrInfo()); + + auto MBBI = MBB.getLastNonDebugInstr(); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + unsigned RetOpcode = MBBI->getOpcode(); + assert(((RetOpcode == AAP::JMP) || (RetOpcode == AAP::JMP_short)) && + "Epilogue can only be inserted in returning blocks"); + + // Number of bytes to dealloc from FrameInfo + const uint64_t StackSize = MFrameInfo.getStackSize(); + uint64_t NumBytes = StackSize - MFuncInfo->getCalleeSavedFrameSize(); + + const unsigned SP = AAPRegisterInfo::getStackPtrRegister(); + + assert(!hasFP(MF) && "Frame pointer unsupported!"); + + if (NumBytes) { + // otherwise adjust by adding back the frame size + const uint64_t Addend = NumBytes % 1023; + const uint64_t NumChunks = NumBytes / 1023; + + for (uint64_t i = 0; i < NumChunks; ++i) { + BuildMI(MBB, MBBI, DL, TII.get(AAP::ADDI_i10), SP) + .addReg(SP) + .addImm(1023); + } + if (Addend) { + BuildMI(MBB, MBBI, DL, TII.get(AAP::ADDI_i10), SP) + .addReg(SP) + .addImm(Addend); + } + } +} + +// This function eliminates ADJCALLSTACKDOWN, +// ADJCALLSTACKUP pseudo instructions +MachineBasicBlock::iterator AAPFrameLowering::eliminateCallFramePseudoInstr( + MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + // FIXME: Implement frame pointer support + assert(!hasFP(MF) && "Frame pointer unsupported!"); + return MBB.erase(I); +} + +void AAPFrameLowering::processFunctionBeforeFrameFinalized( + MachineFunction &MF, RegScavenger *RS) const {} Index: lib/Target/AAP/AAPISelDAGToDAG.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPISelDAGToDAG.cpp @@ -0,0 +1,222 @@ +//===-- AAPISelDAGToDAG.cpp - A dag to dag inst selector for AAP ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the AAP target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "AAP-isel" +#include "AAPMachineFunctionInfo.h" +#include "AAPRegisterInfo.h" +#include "AAPSubtarget.h" +#include "AAPTargetMachine.h" +#include "MCTargetDesc/AAPMCTargetDesc.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// AAPDAGToDAGISel - AAP specific code to select AAP machine +// instructions for SelectionDAG operations. +//===----------------------------------------------------------------------===// +namespace { + +class AAPDAGToDAGISel : public SelectionDAGISel { + + /// TM - Keep a reference to AAPTargetMachine. + AAPTargetMachine &TM; + +public: + AAPDAGToDAGISel(AAPTargetMachine &tm, CodeGenOpt::Level OptLevel) + : SelectionDAGISel(tm), TM(tm) {} + + // Pass Name + virtual StringRef getPassName() const override { + return "AAP DAG->DAG Pattern Instruction Selection"; + } + + bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, + std::vector &OutOps) override; + +// Include the pieces autogenerated from the target description. +#include "AAPGenDAGISel.inc" + +private: + /// getTargetMachine - Return a reference to the TargetMachine, casted + /// to the target-specific type. + const AAPTargetMachine &getTargetMachine() { + return static_cast(TM); + } + + void Select(SDNode *N) override; + + // Complex Pattern for address selection. + bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset); + bool SelectAddr_MO3(SDValue Addr, SDValue &Base, SDValue &Offset); + bool SelectAddr_MO10(SDValue Addr, SDValue &Base, SDValue &Offset); +}; +} // end anonymous namespace + +bool AAPDAGToDAGISel::SelectInlineAsmMemoryOperand( + const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { + switch (ConstraintID) { + default: + return true; + case InlineAsm::Constraint_m: + SDLoc DL(Op); + SDValue RC = + CurDAG->getTargetConstant(AAP::GR64RegClass.getID(), DL, MVT::i16); + SDNode *N = CurDAG->getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DL, + Op.getValueType(), Op, RC); + SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i16); + OutOps.push_back(SDValue(N, 0)); + OutOps.push_back(Zero); + break; + } + return false; +} + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +void AAPDAGToDAGISel::Select(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + SDLoc dl(Node); + + // Dump information about the Node being selected + DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n"); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); + return; + } + + /// + // Instruction Selection not handled by the auto-generated + // tablegen selection should be handled here. + /// + switch (Opcode) { + case ISD::FrameIndex: { + assert(Node->getValueType(0) == MVT::i16); + + int FI = cast(Node)->getIndex(); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i16); + + // Handle single use + SDNode *N = + CurDAG->getMachineNode(AAP::LEA, dl, MVT::i16, TFI, + CurDAG->getTargetConstant(0, dl, MVT::i16)); + ReplaceNode(Node, N); + return; + } + default: + break; + } + + // Select the default instruction + SelectCode(Node); +} + +bool AAPDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { + // if Address is FI, get the TargetFrameIndex + if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { + SDLoc dl(FIN); + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i16); + Offset = CurDAG->getTargetConstant(0, dl, MVT::i16); + return true; + } + + if ((Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress)) { + return false; + } + + bool isConstantOffset = CurDAG->isBaseWithConstantOffset(Addr); + bool isSubOffset = Addr.getOpcode() == ISD::SUB; + + // Addresses of the form Addr+const, Addr-const or Addr|const + if ((isConstantOffset || isSubOffset) && + isa(Addr.getOperand(1))) { + ConstantSDNode *CN = dyn_cast(Addr.getOperand(1)); + SDLoc dl(CN); + + if (isInt<16>(CN->getSExtValue())) { + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = + dyn_cast(Addr.getOperand(0))) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i16); + } else { + Base = Addr.getOperand(0); + } + + int64_t off = CN->getSExtValue(); + if (isConstantOffset) { + Offset = CurDAG->getTargetConstant(off, dl, MVT::i16); + } else { + assert(isSubOffset); + Offset = CurDAG->getTargetConstant(-off, dl, MVT::i16); + } + return true; + } + } + return false; +} + +bool AAPDAGToDAGISel::SelectAddr_MO3(SDValue Addr, SDValue &Base, + SDValue &Offset) { + SDValue B, O; + bool ret = SelectAddr(Addr, B, O); + if (ret) { + int64_t c = dyn_cast(O)->getSExtValue(); + if (AAP::isOff3(c)) { + Base = B; + Offset = O; + return true; + } + } + return false; +} +bool AAPDAGToDAGISel::SelectAddr_MO10(SDValue Addr, SDValue &Base, + SDValue &Offset) { + SDValue B, O; + bool ret = SelectAddr(Addr, B, O); + if (ret) { + int64_t c = dyn_cast(O)->getSExtValue(); + if (AAP::isOff10(c)) { + Base = B; + Offset = O; + return true; + } + } + return false; +} + +/// createAAPISelDag - This pass converts a legalized DAG into a +/// AAP-specific DAG, ready for instruction scheduling. +FunctionPass *llvm::createAAPISelDag(AAPTargetMachine &TM, + CodeGenOpt::Level OptLevel) { + return new AAPDAGToDAGISel(TM, OptLevel); +} Index: lib/Target/AAP/AAPISelLowering.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAPISelLowering.h @@ -0,0 +1,155 @@ +//===-- AAPISelLowering.h - AAP 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 AAP uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef AAPISELLOWERING_H +#define AAPISELLOWERING_H + +#include "AAP.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLowering.h" + +namespace llvm { + +// Forward delcarations +class AAPSubtarget; +class AAPTargetMachine; + +namespace AAPISD { +enum NodeType { + // Start the numbering where the builtin ops and target ops leave off. + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + /// Return with a flag operand. Operand 0 is the chain. + RET_FLAG, + + /// CALL - A node to wrap calls. + CALL, + + /// Wrapper - A wrapper node for TargetConstantPool, TargetExternalSymbol, + /// and TargetGlobalAddress. + Wrapper, + + /// BR_CC - Custom brcc node, where the condition code is an AAP + /// specific value + BR_CC, + + /// SELECT_CC - Custom selectcc node, where the condition code is an + /// AAP specific value + SELECT_CC +}; +} + +//===--------------------------------------------------------------------===// +// TargetLowering Implementation +//===--------------------------------------------------------------------===// +class AAPTargetLowering : public TargetLowering { +public: + explicit AAPTargetLowering(const TargetMachine &TM, const AAPSubtarget &STI); + + /// getTargetNodeName - This method returns the name of a target specific + // DAG node. + const char *getTargetNodeName(unsigned Opcode) const override; + + /// getSetCCResultType - Return the ISD::SETCC ValueType + EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, + EVT VT) const override; + +private: + const AAPSubtarget &Subtarget; + +//===--------------------- Custom DAG Combine ---------------------------===// +public: + SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; + +private: + SDValue PerformADDCombine(SDNode *N, DAGCombinerInfo &DCE) const; + +//===----------------------- Custom Lowering ----------------------------===// +public: + /// LowerOperation - Provide custom lowering hooks for some operations. + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + + /// ReplaceNodeResults - Replace illegal results types for some operations. + void ReplaceNodeResults(SDNode *N, SmallVectorImpl &Results, + SelectionDAG &DAG) const override; + +private: + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; + +//===-------------------- Calling Convention Implementation -------------===// +private: + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + const SDLoc &dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; + + SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const override; + + SDValue LowerCCCCallTo(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool isTailCall, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + const SmallVectorImpl &Ins, + const SDLoc &dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerCCCArguments(SDValue Chain, CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + const SDLoc &dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, + const SDLoc &dl, SelectionDAG &DAG, + SmallVectorImpl &InVals, + uint32_t *RegMask) const; + + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, const SDLoc &dl, + SelectionDAG &DAG) const override; + +//===---------------- AAP Custom Instruction Emissions -------------------===// +public: + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr &MI, + MachineBasicBlock *MBB) const override; + +private: + MachineBasicBlock *emitBrCC(MachineInstr &MI, MachineBasicBlock *MBB) const; + MachineBasicBlock *emitSelectCC(MachineInstr &MI, + MachineBasicBlock *MBB) const; + +//===--------------------- AAP Inline Assembly Support -------------------===// +public: + TargetLowering::ConstraintType + getConstraintType(const StringRef Constraint) const override; + + std::pair + getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, MVT VT) const override; +}; +} + +#endif Index: lib/Target/AAP/AAPISelLowering.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPISelLowering.cpp @@ -0,0 +1,852 @@ +//===-- AAPISelLowering.cpp - AAP 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 AAPTargetLowering class. +// +//===----------------------------------------------------------------------===// + +#include "AAPISelLowering.h" +#include "AAPMachineFunctionInfo.h" +#include "AAPRegisterInfo.h" +#include "AAPSubtarget.h" +#include "MCTargetDesc/AAPMCTargetDesc.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "aap-lower" + +AAPTargetLowering::AAPTargetLowering(const TargetMachine &TM, + const AAPSubtarget &STI) + : TargetLowering(TM), Subtarget(STI) { + + // Set up the register classes. + addRegisterClass(MVT::i16, &AAP::GR8RegClass); + addRegisterClass(MVT::i16, &AAP::GR64RegClass); + computeRegisterProperties(STI.getRegisterInfo()); + + setStackPointerRegisterToSaveRestore(AAPRegisterInfo::getStackPtrRegister()); + setBooleanContents(ZeroOrOneBooleanContent); + setBooleanVectorContents(ZeroOrOneBooleanContent); + + // Only basic load with zero extension i8 -> i16 is supported + // Note: EXTLOAD promotion will trigger an assertion + setLoadExtAction(ISD::EXTLOAD, MVT::i8, MVT::i1, Promote); + setLoadExtAction(ISD::EXTLOAD, MVT::i16, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i8, MVT::i1, Expand); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i16, MVT::i1, Expand); + setLoadExtAction(ISD::SEXTLOAD, MVT::i8, MVT::i1, Expand); + setLoadExtAction(ISD::SEXTLOAD, MVT::i16, MVT::i1, Expand); + setLoadExtAction(ISD::SEXTLOAD, MVT::i16, MVT::i8, Expand); + + setOperationAction(ISD::GlobalAddress, MVT::i16, Custom); + setOperationAction(ISD::ExternalSymbol, MVT::i16, Custom); + setOperationAction(ISD::BlockAddress, MVT::i16, Custom); + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); + + // Handle conditionals via brcc and selectcc + setOperationAction(ISD::BRCOND, MVT::i16, Expand); + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + setOperationAction(ISD::SELECT, MVT::i16, Expand); + setOperationAction(ISD::SETCC, MVT::i16, Expand); + setOperationAction(ISD::SETCC, MVT::Other, Expand); + setOperationAction(ISD::SELECT_CC, MVT::i16, Custom); + setOperationAction(ISD::BR_CC, MVT::i16, Custom); + + // Expand some condition codes which are not natively supported + setCondCodeAction(ISD::SETGT, MVT::i16, Expand); + setCondCodeAction(ISD::SETGE, MVT::i16, Expand); + setCondCodeAction(ISD::SETUGT, MVT::i16, Expand); + setCondCodeAction(ISD::SETUGE, MVT::i16, Expand); + + // Currently no support for indirect branches + setOperationAction(ISD::BRIND, MVT::Other, Expand); + + // No support for jump tables + setOperationAction(ISD::JumpTable, MVT::i16, Expand); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + + // vaarg + setOperationAction(ISD::VASTART, MVT::Other, Custom); + setOperationAction(ISD::VAARG, MVT::Other, Expand); + setOperationAction(ISD::VAEND, MVT::Other, Expand); + setOperationAction(ISD::VACOPY, MVT::Other, Expand); + + // ALU operations unsupported by the architecture + setOperationAction(ISD::SDIV, MVT::i16, Expand); + setOperationAction(ISD::UDIV, MVT::i16, Expand); + setOperationAction(ISD::UREM, MVT::i16, Expand); + setOperationAction(ISD::SREM, MVT::i16, Expand); + setOperationAction(ISD::SDIVREM, MVT::i16, Expand); + setOperationAction(ISD::UDIVREM, MVT::i16, Expand); + + setOperationAction(ISD::MUL, MVT::i16, Expand); + setOperationAction(ISD::MULHS, MVT::i16, Expand); + setOperationAction(ISD::MULHU, MVT::i16, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand); + + // Use ADDE/SUBE + setOperationAction(ISD::SUBC, MVT::i16, Expand); + + setOperationAction(ISD::ROTL, MVT::i16, Expand); + setOperationAction(ISD::ROTR, MVT::i16, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i16, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i16, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i16, Expand); + + setOperationAction(ISD::BSWAP, MVT::i16, Expand); + setOperationAction(ISD::CTTZ, MVT::i16, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i16, Expand); + setOperationAction(ISD::CTLZ, MVT::i16, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i16, Expand); + setOperationAction(ISD::CTPOP, MVT::i16, Expand); + + setOperationAction(ISD::FLT_ROUNDS_, MVT::i32, Custom); + + // Custom DAGCombine + setTargetDAGCombine(ISD::ADD); + + setMinFunctionAlignment(1); + setPrefFunctionAlignment(2); +} + +const char *AAPTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + default: + return nullptr; + case AAPISD::RET_FLAG: + return "AAPISD::RET_FLAG"; + case AAPISD::CALL: + return "AAPISD::CALL"; + case AAPISD::Wrapper: + return "AAPISD::Wrapper"; + case AAPISD::SELECT_CC: + return "AAPISD::SELECT_CC"; + } +} + +EVT AAPTargetLowering::getSetCCResultType(const DataLayout &DL, + LLVMContext &Context, EVT VT) const { + if (!VT.isVector()) { + return MVT::i16; + } + return VT.changeVectorElementTypeToInteger(); +} + +//===----------------------------------------------------------------------===// +// Custom DAG Combine Implementation +//===----------------------------------------------------------------------===// + +SDValue AAPTargetLowering::PerformDAGCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + switch (N->getOpcode()) { + case ISD::ADD: + return PerformADDCombine(N, DCI); + default: + break; + } + return SDValue(); +} + +SDValue AAPTargetLowering::PerformADDCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + + // fold add -ve -> sub +ve + SDValue LHS = N->getOperand(0); + SDValue RHS = N->getOperand(1); + SDLoc DL(N); + + ConstantSDNode *Const = dyn_cast(RHS); + if (!Const) { + return SDValue(); + } + int64_t Value = Const->getSExtValue(); + if (Value >= 0) { + return SDValue(); + } + + RHS = DAG.getConstant(-Value, DL, RHS.getValueType()); + + SDValue Res = DAG.getNode(ISD::SUB, DL, N->getValueType(0), LHS, RHS); + DAG.ReplaceAllUsesWith(N, Res.getNode()); + return SDValue(N, 0); +} + +//===----------------------------------------------------------------------===// +// Custom Lowering Implementation +//===----------------------------------------------------------------------===// + +SDValue AAPTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + case ISD::GlobalAddress: + return LowerGlobalAddress(Op, DAG); + case ISD::ExternalSymbol: + return LowerExternalSymbol(Op, DAG); + case ISD::BlockAddress: + return LowerBlockAddress(Op, DAG); + case ISD::BR_CC: + return LowerBR_CC(Op, DAG); + case ISD::SELECT_CC: + return LowerSELECT_CC(Op, DAG); + case ISD::VASTART: + return LowerVASTART(Op, DAG); + } + llvm_unreachable("unimplemented operand"); +} + +void AAPTargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl &Results, + SelectionDAG &DAG) const { + switch (N->getOpcode()) { + case ISD::FLT_ROUNDS_: + // FLT_ROUNDS has an i32 result type, and can't be expanded. Just lower + // to -1, which corresponds to an unknown default rounding direction. + Results.push_back(DAG.getTargetConstant(-1, SDLoc(N), MVT::i32)); + break; + default: + llvm_unreachable("Unhandled node in ReplaceNodeResults"); + } +} + +// Get the AAP specific condition code for a given CondCode DAG node. +static AAPCC::CondCode getAAPCondCode(ISD::CondCode CC) { + switch (CC) { + // These have a direct equivalent + case ISD::SETEQ: + return AAPCC::COND_EQ; + case ISD::SETNE: + return AAPCC::COND_NE; + case ISD::SETLT: + return AAPCC::COND_LTS; + case ISD::SETLE: + return AAPCC::COND_LES; + case ISD::SETULT: + return AAPCC::COND_LTU; + case ISD::SETULE: + return AAPCC::COND_LEU; + // Other condition codes are unhandled + default: + llvm_unreachable("Unknown condition for brcc lowering"); + return AAPCC::COND_INVALID; + } +} + +SDValue AAPTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(Op); + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue BranchTarget = Op.getOperand(4); + + // get equivalent AAP condition code + AAPCC::CondCode TargetCC = getAAPCondCode(CC); + + SDValue Ops[] = {Chain, DAG.getConstant(TargetCC, DL, MVT::i16), LHS, RHS, + BranchTarget}; + return DAG.getNode(AAPISD::BR_CC, DL, Op.getValueType(), Ops); +} + +SDValue AAPTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(Op); + + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + SDValue TrueValue = Op.getOperand(2); + SDValue FalseValue = Op.getOperand(3); + ISD::CondCode CC = cast(Op.getOperand(4))->get(); + + // get equivalent AAP condition code + AAPCC::CondCode TargetCC = getAAPCondCode(CC); + + SDValue Ops[] = {LHS, RHS, TrueValue, FalseValue, + DAG.getConstant(TargetCC, DL, MVT::i16)}; + return DAG.getNode(AAPISD::SELECT_CC, DL, Op.getValueType(), Ops); +} + +SDValue AAPTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + AAPMachineFunctionInfo *MFI = MF.getInfo(); + const DataLayout &DL = DAG.getDataLayout(); + + // Frame index of first vaarg argument + SDValue FrameIndex = + DAG.getFrameIndex(MFI->getVarArgsFrameIndex(), getPointerTy(DL)); + const Value *Src = cast(Op.getOperand(2))->getValue(); + + // Create a store of the frame index to the location operand + return DAG.getStore(Op.getOperand(0), SDLoc(Op), FrameIndex, Op.getOperand(1), + MachinePointerInfo(Src)); +} + +SDValue AAPTargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + const DataLayout DL = DAG.getDataLayout(); + const GlobalValue *GV = cast(Op)->getGlobal(); + int64_t Offset = cast(Op)->getOffset(); + SDValue Result = + DAG.getTargetGlobalAddress(GV, SDLoc(Op), getPointerTy(DL), Offset); + return DAG.getNode(AAPISD::Wrapper, SDLoc(Op), getPointerTy(DL), Result); +} + +SDValue AAPTargetLowering::LowerExternalSymbol(SDValue Op, + SelectionDAG &DAG) const { + const DataLayout DL = DAG.getDataLayout(); + const char *Sym = cast(Op)->getSymbol(); + SDValue Result = DAG.getTargetExternalSymbol(Sym, getPointerTy(DL)); + return DAG.getNode(AAPISD::Wrapper, SDLoc(Op), getPointerTy(DL), Result); +} + +SDValue AAPTargetLowering::LowerBlockAddress(SDValue Op, + SelectionDAG &DAG) const { + const DataLayout DL = DAG.getDataLayout(); + const BlockAddress *BA = cast(Op)->getBlockAddress(); + SDValue Result = DAG.getTargetBlockAddress(BA, getPointerTy(DL)); + return DAG.getNode(AAPISD::Wrapper, SDLoc(Op), getPointerTy(DL), Result); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +#include "AAPGenCallingConv.inc" + +/// For each argument in a function store the number of pieces it is composed +/// of. +template +static void ParseFunctionArgs(const SmallVectorImpl &Args, + SmallVectorImpl &Out) { + unsigned CurrentArgIndex = ~0U; + for (unsigned i = 0, e = Args.size(); i != e; i++) { + if (CurrentArgIndex == Args[i].OrigArgIndex) { + Out.back()++; + } else { + Out.push_back(1); + CurrentArgIndex++; + } + } +} + +SDValue AAPTargetLowering::LowerFormalArguments( + SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl &InVals) const { + + switch (CallConv) { + default: + llvm_unreachable("Unsupported calling convention"); + case CallingConv::C: + case CallingConv::Fast: + return LowerCCCArguments(Chain, CallConv, isVarArg, Ins, DL, DAG, InVals); + } +} + +SDValue AAPTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const { + SelectionDAG &DAG = CLI.DAG; + SDLoc &DL = CLI.DL; + SmallVectorImpl &Outs = CLI.Outs; + SmallVectorImpl &OutVals = CLI.OutVals; + SmallVectorImpl &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &isTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool isVarArg = CLI.IsVarArg; + + // AAP target does not yet support tail call optimization. + isTailCall = false; + + switch (CallConv) { + default: + llvm_unreachable("Unsupported calling convention"); + case CallingConv::Fast: + case CallingConv::C: + return LowerCCCCallTo(Chain, Callee, CallConv, isVarArg, isTailCall, Outs, + OutVals, Ins, DL, DAG, InVals); + } +} + +/// LowerCCCArguments - transform physical registers into virtual registers and +/// generate load operations for arguments places on the stack. +SDValue AAPTargetLowering::LowerCCCArguments( + SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + AAPMachineFunctionInfo *FuncInfo = MF.getInfo(); + + // Assign locations to all of the incoming arguments. + SmallVector ArgLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs, + *DAG.getContext()); + CCInfo.AnalyzeFormalArguments(Ins, CC_AAP); + + // Create frame index for the start of the first vararg value + if (isVarArg) { + unsigned Offset = CCInfo.getNextStackOffset(); + FuncInfo->setVarArgsFrameIndex(MFI.CreateFixedObject(1, Offset, true)); + } + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + if (VA.isRegLoc()) { + // Arguments passed in registers + EVT RegVT = VA.getLocVT(); + switch (RegVT.getSimpleVT().SimpleTy) { + default: { +#ifndef NDEBUG + errs() << "LowerFormalArguments Unhandled argument type: " + << RegVT.getEVTString() << "\n"; +#endif + llvm_unreachable(0); + } + case MVT::i16: + unsigned VReg = RegInfo.createVirtualRegister(&AAP::GR64RegClass); + RegInfo.addLiveIn(VA.getLocReg(), VReg); + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, VReg, RegVT); + + // If this is an 8-bit value, it is really passed promoted to 16 + // bits. Insert an assert[sz]ext to capture this, then truncate to the + // right size. + if (VA.getLocInfo() == CCValAssign::SExt) + ArgValue = DAG.getNode(ISD::AssertSext, DL, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + ArgValue = DAG.getNode(ISD::AssertZext, DL, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + + if (VA.getLocInfo() != CCValAssign::Full) + ArgValue = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), ArgValue); + + InVals.push_back(ArgValue); + } + } else { + // Sanity check + assert(VA.isMemLoc()); + + SDValue InVal; + ISD::ArgFlagsTy Flags = Ins[i].Flags; + + if (Flags.isByVal()) { + int FI = MFI.CreateFixedObject(Flags.getByValSize(), + VA.getLocMemOffset(), true); + InVal = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + } else { + // Load the argument to a virtual register + unsigned ObjSize = VA.getLocVT().getSizeInBits() / 8; + if (ObjSize > 2) { + errs() << "LowerFormalArguments Unhandled argument type: " + << EVT(VA.getLocVT()).getEVTString() << "\n"; + } + // Create the frame index object for this incoming parameter... + int FI = MFI.CreateFixedObject(ObjSize, VA.getLocMemOffset(), true); + + // Create the SelectionDAG nodes corresponding to a load + // from this parameter + SDValue FIN = DAG.getFrameIndex(FI, MVT::i16); + InVal = DAG.getLoad(VA.getLocVT(), DL, Chain, FIN, + MachinePointerInfo::getFixedStack(MF, FI)); + } + + InVals.push_back(InVal); + } + } + + return Chain; +} + +SDValue +AAPTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + const SDLoc &DL, SelectionDAG &DAG) const { + + // CCValAssign - represent the assignment of the return value to a location + SmallVector RVLocs; + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs, + *DAG.getContext()); + + // Analize return values. + CCInfo.AnalyzeReturn(Outs, RetCC_AAP); + + SDValue Flag; + SmallVector RetOps(1, Chain); + + // Add the link register as the first operand + RetOps.push_back( + DAG.getRegister(AAPRegisterInfo::getLinkRegister(), MVT::i16)); + + // Add return registers to the CalleeSaveDisableRegs list. + MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo(); + for (unsigned i = 0; i != RVLocs.size(); ++i) { + MRI.disableCalleeSavedRegister(RVLocs[i].getLocReg()); + } + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Flag); + + // Guarantee that all emitted copies are stuck together, + // avoiding something bad. + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + + RetOps[0] = Chain; // Update chain. + + // Add the flag if we have it. + if (Flag.getNode()) + RetOps.push_back(Flag); + + return DAG.getNode(AAPISD::RET_FLAG, DL, {MVT::Other, MVT::i16}, RetOps); +} + +/// LowerCCCCallTo - functions arguments are copied from virtual regs to +/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. +SDValue AAPTargetLowering::LowerCCCCallTo( + SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool isVarArg, + bool isTailCall, const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + const SmallVectorImpl &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl &InVals) const { + const DataLayout &TD = DAG.getDataLayout(); + + // Analyze operands of the call, assigning locations to each operand. + SmallVector ArgLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs, + *DAG.getContext()); + + CCInfo.AnalyzeCallOperands(Outs, CC_AAP); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = CCInfo.getNextStackOffset(); + + Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, DL); + + SmallVector, 4> RegsToPass; + SmallVector MemOpChains; + SDValue StackPtr; + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + + SDValue Arg = OutVals[i]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: + break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg); + break; + } + + // Arguments that can be passed on register must be kept at RegsToPass + // vector + if (VA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + } else { + assert(VA.isMemLoc()); + + if (StackPtr.getNode() == 0) + StackPtr = DAG.getCopyFromReg(Chain, DL, + AAPRegisterInfo::getStackPtrRegister(), + getPointerTy(TD)); + + SDValue PtrOff = + DAG.getNode(ISD::ADD, DL, getPointerTy(TD), StackPtr, + DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); + + SDValue MemOp; + ISD::ArgFlagsTy Flags = Outs[i].Flags; + + if (Flags.isByVal()) { + SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), DL, MVT::i16); + MemOp = DAG.getMemcpy( + Chain, DL, PtrOff, Arg, SizeNode, Flags.getByValAlign(), + /*isVolatile*/ false, + /*AlwaysInline*/ true, + /*isTailCall*/ false, MachinePointerInfo(), MachinePointerInfo()); + } else { + MemOp = DAG.getStore(Chain, DL, Arg, PtrOff, MachinePointerInfo()); + } + + MemOpChains.push_back(MemOp); + } + } + + // Transform all store nodes into one single node because all store nodes are + // independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); + + // Build a sequence of copy-to-reg nodes chained together with token chain and + // flag operands which copy the outgoing args into registers. The InFlag in + // necessary since all emitted instructions must be stuck together. + SDValue InFlag; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, DL, RegsToPass[i].first, + RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + // Likewise ExternalSymbol -> TargetExternalSymbol. + if (GlobalAddressSDNode *G = dyn_cast(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, MVT::i16); + else if (ExternalSymbolSDNode *E = dyn_cast(Callee)) + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i16); + + // Returns a chain & a flag for retval copy to use. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add the link register as the first operand + Ops.push_back(DAG.getRegister(AAPRegisterInfo::getLinkRegister(), MVT::i16)); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + + // Add the caller saved registers as a register mask operand to the call + MachineFunction &MF = DAG.getMachineFunction(); + const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); + const uint32_t *Mask = + TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv); + assert(Mask && "No call preserved mask for the calling convention"); + + // Define a new dynamic register mask based on the exiting static mask. + uint32_t *RegMask = MF.allocateRegisterMask(TRI->getNumRegs()); + unsigned RegMaskSize = (TRI->getNumRegs() + 31) / 32; + memcpy(RegMask, Mask, sizeof(uint32_t) * RegMaskSize); + + // Create the RegMask Operand according to our dynamic mask, the dynamic + // mask will be updated in LowerCallResult + Ops.push_back(DAG.getRegisterMask(RegMask)); + + if (InFlag.getNode()) + Ops.push_back(InFlag); + + Chain = DAG.getNode(AAPISD::CALL, DL, NodeTys, Ops); + InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END( + Chain, DAG.getConstant(NumBytes, DL, getPointerTy(TD), true), + DAG.getConstant(0, DL, getPointerTy(TD), true), InFlag, DL); + InFlag = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, DL, DAG, + InVals, RegMask); +} + +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers. +/// +SDValue AAPTargetLowering::LowerCallResult( + SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl &InVals, + uint32_t *RegMask) const { + // Assign locations to each value returned by this call. + SmallVector RVLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs, + *DAG.getContext()); + + CCInfo.AnalyzeCallResult(Ins, RetCC_AAP); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + Chain = DAG.getCopyFromReg(Chain, DL, RVLocs[i].getLocReg(), + RVLocs[i].getValVT(), InFlag) + .getValue(1); + InFlag = Chain.getValue(2); + InVals.push_back(Chain.getValue(0)); + } + + // For the calling convention we need to remove the used registers from + // the register mask + for (unsigned i = 0; i != RVLocs.size(); ++i) { + unsigned Reg = RVLocs[i].getLocReg(); + RegMask[Reg / 32] &= ~(1u << (Reg & 32)); + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// AAP Custom Instruction Emission +//===----------------------------------------------------------------------===// + +MachineBasicBlock * +AAPTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, + MachineBasicBlock *MBB) const { + switch (MI.getOpcode()) { + case AAP::BR_CC: + return emitBrCC(MI, MBB); + case AAP::SELECT_CC: + return emitSelectCC(MI, MBB); + default: + llvm_unreachable("Unexpected instruction for custom insertion"); + } +} + +MachineBasicBlock *AAPTargetLowering::emitBrCC(MachineInstr &MI, + MachineBasicBlock *MBB) const { + const auto &STI = MBB->getParent()->getSubtarget(); + const auto &TII = *static_cast(STI.getInstrInfo()); + DebugLoc DL = MI.getDebugLoc(); + AAPCC::CondCode CC = (AAPCC::CondCode)MI.getOperand(0).getImm(); + + unsigned LhsReg = MI.getOperand(1).getReg(); + unsigned RhsReg = MI.getOperand(2).getReg(); + MachineBasicBlock *TargetMBB = MI.getOperand(3).getMBB(); + + unsigned BranchOp = TII.getBranchOpcodeFromCond(CC); + BuildMI(*MBB, &MI, DL, TII.get(BranchOp)) + .addMBB(TargetMBB) + .addReg(LhsReg) + .addReg(RhsReg); + + MI.eraseFromParent(); + return MBB; +} + +MachineBasicBlock * +AAPTargetLowering::emitSelectCC(MachineInstr &MI, + MachineBasicBlock *MBB) const { + const auto &STI = MBB->getParent()->getSubtarget(); + const auto &TII = *static_cast(STI.getInstrInfo()); + DebugLoc DL = MI.getDebugLoc(); + + // insert a diamond control flow pattern to handle the select + const BasicBlock *BB = MBB->getBasicBlock(); + MachineFunction::iterator It = MBB->getIterator(); + ++It; + + MachineBasicBlock *EntryMBB = MBB; + MachineFunction *MF = MBB->getParent(); + MachineBasicBlock *FalseValueMBB = MF->CreateMachineBasicBlock(BB); + MachineBasicBlock *SinkMBB = MF->CreateMachineBasicBlock(BB); + MF->insert(It, FalseValueMBB); + MF->insert(It, SinkMBB); + + // Transfer remainder of entryBB to sinkMBB + SinkMBB->splice(SinkMBB->begin(), EntryMBB, + std::next(MachineBasicBlock::iterator(MI)), EntryMBB->end()); + SinkMBB->transferSuccessorsAndUpdatePHIs(EntryMBB); + + // Add false value and fallthrough blocks as successors + EntryMBB->addSuccessor(FalseValueMBB); + EntryMBB->addSuccessor(SinkMBB); + + AAPCC::CondCode CC = (AAPCC::CondCode)MI.getOperand(5).getImm(); + unsigned BranchOp = TII.getBranchOpcodeFromCond(CC); + + unsigned InReg = MI.getOperand(0).getReg(); + unsigned LhsReg = MI.getOperand(1).getReg(); + unsigned RhsReg = MI.getOperand(2).getReg(); + BuildMI(EntryMBB, DL, TII.get(BranchOp)) + .addMBB(SinkMBB) + .addReg(LhsReg) + .addReg(RhsReg); + + FalseValueMBB->addSuccessor(SinkMBB); + + unsigned TrueValueReg = MI.getOperand(3).getReg(); + unsigned FalseValueReg = MI.getOperand(4).getReg(); + BuildMI(*SinkMBB, SinkMBB->begin(), DL, TII.get(AAP::PHI), InReg) + .addReg(TrueValueReg) + .addMBB(EntryMBB) + .addReg(FalseValueReg) + .addMBB(FalseValueMBB); + + MI.eraseFromParent(); + return SinkMBB; +} + +//===----------------------------------------------------------------------===// +// AAP Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target +TargetLowering::ConstraintType +AAPTargetLowering::getConstraintType(StringRef Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default: + break; + case 'r': + return C_RegisterClass; + } + } + return TargetLowering::getConstraintType(Constraint); +} + +std::pair +AAPTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, + MVT VT) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default: + break; + case 'r': + // General purpose registers + return std::make_pair(0U, &AAP::GR64RegClass); + } + } + return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); +} Index: lib/Target/AAP/AAPInstrInfo.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAPInstrInfo.h @@ -0,0 +1,73 @@ +//===-- AAPInstrInfo.h - AAP 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 AAP implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef AAPINSTRINFO_H +#define AAPINSTRINFO_H + +#include "AAP.h" +#include "AAPRegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "AAPGenInstrInfo.inc" + +namespace llvm { + +class AAPSubtarget; + +class AAPInstrInfo : public AAPGenInstrInfo { + const AAPRegisterInfo TRI; + virtual void anchor(); + +public: + AAPInstrInfo(AAPSubtarget &STI); + + const TargetRegisterInfo &getRegisterInfo() const { return TRI; } + + AAPCC::CondCode getCondFromBranchOpcode(unsigned Opcode) const; + unsigned getBranchOpcodeFromCond(AAPCC::CondCode CC) const; + + bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify = false) const override; + + unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef Cond, + const DebugLoc &DL, + int *BytesAdded = nullptr) const override; + + unsigned removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved = nullptr) const override; + + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, + bool KillSrc) const override; + + void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, unsigned SrcReg, + bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + + void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, unsigned DestReg, + int FrameIndex, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + + bool + reverseBranchCondition(SmallVectorImpl &Cond) const override; +}; +} + +#endif Index: lib/Target/AAP/AAPInstrInfo.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPInstrInfo.cpp @@ -0,0 +1,345 @@ +//===-- AAPInstrInfo.cpp - AAP Instruction Information ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the AAP implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "AAPInstrInfo.h" +#include "AAPMachineFunctionInfo.h" +#include "MCTargetDesc/AAPMCTargetDesc.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define GET_INSTRINFO_CTOR_DTOR +#include "AAPGenInstrInfo.inc" + +// Pin the vtable to this file. +void AAPInstrInfo::anchor() {} + +AAPInstrInfo::AAPInstrInfo(AAPSubtarget &STI) + : AAPGenInstrInfo(AAP::ADJCALLSTACKDOWN, AAP::ADJCALLSTACKUP), TRI() {} + +//===----------------------------------------------------------------------===// +// Branch Analysis +//===----------------------------------------------------------------------===// + +AAPCC::CondCode AAPInstrInfo::getCondFromBranchOpcode(unsigned Opcode) const { + switch (Opcode) { + default: + return AAPCC::COND_INVALID; + case AAP::BEQ_: + return AAPCC::COND_EQ; + case AAP::BNE_: + return AAPCC::COND_NE; + case AAP::BLTS_: + return AAPCC::COND_LTS; + case AAP::BLES_: + return AAPCC::COND_LES; + case AAP::BLTU_: + return AAPCC::COND_LTU; + case AAP::BLEU_: + return AAPCC::COND_LEU; + } +} + +unsigned AAPInstrInfo::getBranchOpcodeFromCond(AAPCC::CondCode CC) const { + switch (CC) { + default: + llvm_unreachable("Invalid condition code"); + case AAPCC::COND_EQ: + return AAP::BEQ_; + case AAPCC::COND_NE: + return AAP::BNE_; + case AAPCC::COND_LTS: + return AAP::BLTS_; + case AAPCC::COND_LES: + return AAP::BLES_; + case AAPCC::COND_LTU: + return AAP::BLTU_; + case AAPCC::COND_LEU: + return AAP::BLEU_; + } +} + +bool AAPInstrInfo::analyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const { + // Find the first unconditional branch + MachineBasicBlock::iterator I = MBB.end(); + MachineBasicBlock::iterator CondBrIter = MBB.end(); + MachineBasicBlock::iterator UnCondBrIter = MBB.end(); + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + + // If we see a non-terminator, we're done + if (!isUnpredicatedTerminator(*I)) + break; + // Unconditional branch opcode + if (I->getOpcode() == AAP::BRA) + UnCondBrIter = I; + } + + // Find either: + // - The first conditional branch before an unconditional branch + // - The first conditional branch, if no unconditional branch was found + if (UnCondBrIter == MBB.end()) + I = MBB.end(); + else + I = UnCondBrIter; + unsigned NumCondBr = 0; + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + + // If we see a non-terminator, we're done + if (!isUnpredicatedTerminator(*I)) + break; + + // Conditional branch opcode + switch (I->getOpcode()) { + default: + break; + case AAP::BEQ_: + case AAP::BNE_: + case AAP::BLTS_: + case AAP::BLES_: + case AAP::BLTU_: + case AAP::BLEU_: + ++NumCondBr; + CondBrIter = I; + } + } + + // If there's more than one conditional branch, we can't analyze it + // TODO: Relax this constraint. We should be able to handle things such as: + // beq L1, r0, r1 + // bne L2, r0, r1 + // More elegantly + if (NumCondBr > 1) + return true; + + bool HaveCondBr = CondBrIter != MBB.end(); + bool HaveUnCondBr = UnCondBrIter != MBB.end(); + + if (AllowModify && HaveUnCondBr) { + // Nuke everything after the first unconditional branch + while (std::next(UnCondBrIter) != MBB.end()) + std::next(UnCondBrIter)->eraseFromParent(); + + // Remove the unconditional branch if it's actually a fallthrough + if (MBB.isLayoutSuccessor(UnCondBrIter->getOperand(0).getMBB())) { + UnCondBrIter->eraseFromParent(); + HaveUnCondBr = false; + } + + if (HaveCondBr && HaveUnCondBr) { + // We may be able to modify the following code: + // + // bCC L1 + // bra L2 + // L1: + // ... + // L2: + // + // To something more efficient such as + // + // bnCC L2 + // L1: + // ... + // L2: + // + if (MBB.isLayoutSuccessor(CondBrIter->getOperand(0).getMBB())) { + unsigned Opcode = CondBrIter->getOpcode(); + if (Opcode == AAP::BEQ_ || Opcode == AAP::BNE_) { + unsigned InvertedOpcode = Opcode == AAP::BEQ_ ? AAP::BNE_ : AAP::BEQ_; + + MachineBasicBlock *Target = UnCondBrIter->getOperand(0).getMBB(); + DebugLoc DL = MBB.findDebugLoc(CondBrIter); + + MachineInstr *OldCondBr = &*CondBrIter; + MachineInstrBuilder MIB; + CondBrIter = BuildMI(&MBB, DL, get(InvertedOpcode)) + .addMBB(Target) + .addReg(CondBrIter->getOperand(1).getReg()) + .addReg(CondBrIter->getOperand(2).getReg()); + + // Replace the conditional branch with the inverted branch + UnCondBrIter->eraseFromParent(); + OldCondBr->eraseFromParent(); + HaveUnCondBr = false; + } + } + } + } + + if (!HaveUnCondBr && !HaveCondBr) { + // Block ends with no branches (falls through to its successor) + TBB = FBB = nullptr; + } else if (HaveUnCondBr && HaveCondBr) { + // Unconditional branch preceded by conditional branch + TBB = CondBrIter->getOperand(0).getMBB(); + FBB = UnCondBrIter->getOperand(0).getMBB(); + + AAPCC::CondCode CC = getCondFromBranchOpcode(CondBrIter->getOpcode()); + Cond.push_back(MachineOperand::CreateImm(CC)); + Cond.push_back(CondBrIter->getOperand(1)); + Cond.push_back(CondBrIter->getOperand(2)); + } else if (HaveUnCondBr && !HaveCondBr) { + // Only an unconditional branch, set TBB to the destination block + TBB = UnCondBrIter->getOperand(0).getMBB(); + } else { + assert(!HaveUnCondBr && HaveCondBr); + // Conditional branch /w fallthrough. Set TBB to destination and + // set Cond to operands to evaluate the condition + TBB = CondBrIter->getOperand(0).getMBB(); + AAPCC::CondCode CC = getCondFromBranchOpcode(CondBrIter->getOpcode()); + Cond.push_back(MachineOperand::CreateImm(CC)); + Cond.push_back(CondBrIter->getOperand(1)); + Cond.push_back(CondBrIter->getOperand(2)); + } + return false; +} + +unsigned AAPInstrInfo::insertBranch(MachineBasicBlock &MBB, + MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + ArrayRef Cond, + const DebugLoc &DL, + int *BytesAdded) const { + assert(TBB && "InsertBranch cannot insert a fallthrough"); + assert(Cond.size() == 3 || Cond.size() == 0); + assert(!BytesAdded && "Code size not handled"); + + if (Cond.empty()) { + assert(!FBB && "Unconditional branch cannot have multiple successors"); + BuildMI(&MBB, DL, get(AAP::BRA)).addMBB(TBB); + return 1; + } + // Conditional branch + unsigned Count = 0; + AAPCC::CondCode CC = (AAPCC::CondCode)Cond[0].getImm(); + BuildMI(&MBB, DL, get(getBranchOpcodeFromCond(CC))) + .addMBB(TBB) + .addReg(Cond[1].getReg()) + .addReg(Cond[2].getReg()); + ++Count; + + if (FBB) { + BuildMI(&MBB, DL, get(AAP::BRA)).addMBB(FBB); + ++Count; + } + return Count; +} + +unsigned AAPInstrInfo::removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved) const { + assert(!BytesRemoved && "Code size not handled"); + + unsigned Count = 0; + auto I = MBB.end(); + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + if (!I->isBranch()) + break; + // Remove the branch + I->eraseFromParent(); + I = MBB.end(); + ++Count; + } + return Count; +} + +void AAPInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + const DebugLoc &DL, unsigned DestReg, + unsigned SrcReg, bool KillSrc) const { + assert(AAP::GR64RegClass.contains(DestReg) && + AAP::GR64RegClass.contains(DestReg) && + "Impossible register-register copy"); + + // FIXME: If possible with short insn, build that instead + BuildMI(MBB, I, DL, get(AAP::MOV_r), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); +} + +void AAPInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, + int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFrameInfo = MF.getFrameInfo(); + + DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc(); + + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getFixedStack(MF, FrameIdx), + MachineMemOperand::MOStore, MFrameInfo.getObjectSize(FrameIdx), + MFrameInfo.getObjectAlignment(FrameIdx)); + + assert((RC == &AAP::GR8RegClass || RC == &AAP::GR64RegClass) && + "Unknown register class to store to stack slot"); + + BuildMI(MBB, MI, DL, get(AAP::STW)) + .addFrameIndex(FrameIdx) + .addImm(0) + .addReg(SrcReg, getKillRegState(isKill)) + .addMemOperand(MMO); +} + +void AAPInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DstReg, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFrameInfo = MF.getFrameInfo(); + + DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc(); + + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getFixedStack(MF, FrameIdx), + MachineMemOperand::MOLoad, MFrameInfo.getObjectSize(FrameIdx), + MFrameInfo.getObjectAlignment(FrameIdx)); + + assert((RC == &AAP::GR8RegClass || RC == &AAP::GR64RegClass) && + "Unknown register class to store to stack slot"); + + BuildMI(MBB, MI, DL, get(AAP::LDW), DstReg) + .addFrameIndex(FrameIdx) + .addImm(0) + .addMemOperand(MMO); +} + +/// ReverseBranchCondition - Return the inverse opcode of the +/// specified Branch instruction. +bool AAPInstrInfo::reverseBranchCondition( + SmallVectorImpl &Cond) const { + return false; +} Index: lib/Target/AAP/AAPMCInstLower.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAPMCInstLower.h @@ -0,0 +1,47 @@ +//===-- AAPMCInstLower.h - Lower MachineInstr to MCInst ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_AAP_AAPMCINSTLOWER_H +#define LLVM_LIB_TARGET_AAP_AAPMCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { +class AsmPrinter; +class MCContext; +class MCInst; +class MCOperand; +class MCSymbol; +class MachineInstr; +class MachineModuleInfoMachO; +class MachineOperand; + +/// AAPMCInstLower - This class is used to lower an MachineInstr +/// into an MCInst. +class LLVM_LIBRARY_VISIBILITY AAPMCInstLower { + MCContext &Ctx; + + AsmPrinter &Printer; + +public: + AAPMCInstLower(MCContext &ctx, AsmPrinter &printer) + : Ctx(ctx), Printer(printer) {} + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; + MCSymbol *GetBlockAddressSymbol(const MachineOperand &MO) const; +}; +} + +#endif Index: lib/Target/AAP/AAPMCInstLower.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPMCInstLower.cpp @@ -0,0 +1,168 @@ +//===-- AAPMCInstLower.cpp - Convert AAP MachineInstr to an MCInst --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower AAP MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "AAPMCInstLower.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +MCSymbol * +AAPMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + case 0: + break; + } + + return Printer.getSymbol(MO.getGlobal()); +} + +MCSymbol * +AAPMCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const { + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + case 0: + break; + } + + return Printer.GetExternalSymbolSymbol(MO.getSymbolName()); +} + +MCSymbol *AAPMCInstLower::GetJumpTableSymbol(const MachineOperand &MO) const { + const DataLayout &DL = Printer.getDataLayout(); + SmallString<256> Name; + raw_svector_ostream(Name) << DL.getPrivateGlobalPrefix() << "JTI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + case 0: + break; + } + + // Create a symbol for the name. + return Ctx.getOrCreateSymbol(Name); +} + +MCSymbol * +AAPMCInstLower::GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + const DataLayout &DL = Printer.getDataLayout(); + SmallString<256> Name; + raw_svector_ostream(Name) << DL.getPrivateGlobalPrefix() << "CPI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + case 0: + break; + } + + // Create a symbol for the name. + return Ctx.getOrCreateSymbol(Name); +} + +MCSymbol * +AAPMCInstLower::GetBlockAddressSymbol(const MachineOperand &MO) const { + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + case 0: + break; + } + + return Printer.GetBlockAddressSymbol(MO.getBlockAddress()); +} + +MCOperand AAPMCInstLower::LowerSymbolOperand(const MachineOperand &MO, + MCSymbol *Sym) const { + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx); + + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + case 0: + break; + } + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::createAdd( + Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); + return MCOperand::createExpr(Expr); +} + +void AAPMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->dump(); + llvm_unreachable("unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) + continue; + MCOp = MCOperand::createReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::createImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::createExpr( + MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); + break; + case MachineOperand::MO_BlockAddress: + MCOp = LowerSymbolOperand(MO, GetBlockAddressSymbol(MO)); + break; + case MachineOperand::MO_RegisterMask: + continue; + } + + OutMI.addOperand(MCOp); + } +} Index: lib/Target/AAP/AAPMachineFunctionInfo.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAPMachineFunctionInfo.h @@ -0,0 +1,65 @@ +//===- AAPMachineFuctionInfo.h - AAP machine func info -----------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares AAP-specific per-machine-function information. +// +//===----------------------------------------------------------------------===// + +#ifndef AAPMACHINEFUNCTIONINFO_H +#define AAPMACHINEFUNCTIONINFO_H +#include "AAPRegisterInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +namespace llvm { + +/// AAPMachineFunctionInfo - This class is derived from MachineFunction and +/// contains private AAP target-specific information for each MachineFunction. +class AAPMachineFunctionInfo : public MachineFunctionInfo { + virtual void anchor(); + + MachineFunction &MF; + + /// CalleeSavedFrameSize - Size of the callee-saved register portion of the + /// stack frame in bytes + unsigned CalleeSavedFrameSize; + + /// SRetReturnReg - AAP ABI require that sret lowering includes + /// returning the value of the returned struct in a register. This field + /// holds the virtual register into which the sret argument is passed. + unsigned SRetReturnReg; + + /// GlobalBaseReg - keeps track of the virtual register initialized for + /// use as the global base register. This is used for PIC in some PIC + /// relocation models. + unsigned GlobalBaseReg; + + /// VarArgsFrameIndex - FrameIndex for start of varargs area. + int VarArgsFrameIndex; + +public: + AAPMachineFunctionInfo(MachineFunction &MF) + : MF(MF), CalleeSavedFrameSize(0), SRetReturnReg(0), GlobalBaseReg(0), + VarArgsFrameIndex(0) {} + + unsigned getCalleeSavedFrameSize() { return CalleeSavedFrameSize; } + void setCalleeSavedFrameSize(unsigned bytes) { CalleeSavedFrameSize = bytes; } + + unsigned getSRetReturnReg() const { return SRetReturnReg; } + void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; } + + unsigned getGlobalBaseReg(); + + int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } + void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } +}; + +} // End llvm namespace + +#endif Index: lib/Target/AAP/AAPMachineFunctionInfo.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPMachineFunctionInfo.cpp @@ -0,0 +1,23 @@ +//===-- AAPMachineFuctionInfo.cpp - AAP machine function info -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AAPMachineFunctionInfo.h" + +using namespace llvm; + +void AAPMachineFunctionInfo::anchor() {} + +unsigned AAPMachineFunctionInfo::getGlobalBaseReg() { + // Return if it has already been initialized. + if (GlobalBaseReg) + return GlobalBaseReg; + + return GlobalBaseReg = + MF.getRegInfo().createVirtualRegister(&AAP::GR64RegClass); +} Index: lib/Target/AAP/AAPRegisterInfo.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAPRegisterInfo.h @@ -0,0 +1,54 @@ +//===-- AAPRegisterInfo.h - AAP 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 AAP implementation of the MRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef AAPREGISTERINFO_H +#define AAPREGISTERINFO_H + +#include "llvm/Target/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "AAPGenRegisterInfo.inc" + +namespace llvm { + +class TargetInstrInfo; + +struct AAPRegisterInfo : public AAPGenRegisterInfo { +public: + AAPRegisterInfo(); + + const MCPhysReg * + getCalleeSavedRegs(const MachineFunction *MF = nullptr) const override; + + const uint32_t *getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID ID) const override; + + BitVector getReservedRegs(const MachineFunction &MF) const override; + + bool requiresRegisterScavenging(const MachineFunction &MF) const override; + + void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + unsigned FIOperandNum, + RegScavenger *RS = nullptr) const override; + + // Debug information queries. + unsigned getFrameRegister(const MachineFunction &MF) const override; + + static unsigned getLinkRegister(); + static unsigned getStackPtrRegister(); + static unsigned getFramePtrRegister(); +}; + +} // end namespace llvm + +#endif Index: lib/Target/AAP/AAPRegisterInfo.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPRegisterInfo.cpp @@ -0,0 +1,119 @@ +//===-- AAPRegisterInfo.cpp - AAP 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 AAP implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "AAPRegisterInfo.h" +#include "AAPSubtarget.h" +#include "MCTargetDesc/AAPMCTargetDesc.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" + +using namespace llvm; + +#define GET_REGINFO_TARGET_DESC +#include "AAPGenRegisterInfo.inc" +#include "llvm/CodeGen/MachineFunction.h" + +AAPRegisterInfo::AAPRegisterInfo() : AAPGenRegisterInfo(getLinkRegister()) {} + +const MCPhysReg * +AAPRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + return CSR_SaveList; +} + +const uint32_t *AAPRegisterInfo::getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID) const { + return CSR_RegMask; +} + +BitVector AAPRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + + Reserved.set(getLinkRegister()); + Reserved.set(getStackPtrRegister()); + if (TFI->hasFP(MF)) { + Reserved.set(getFramePtrRegister()); + } + + return Reserved; +} + +bool AAPRegisterInfo::requiresRegisterScavenging( + const MachineFunction &MF) const { + return false; +} + +void AAPRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MBBI, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const { + MachineInstr &MI = *MBBI; + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + + DebugLoc DL = MI.getDebugLoc(); + + unsigned i = 0; + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && + "Instr does not have a Frame Index operand!"); + } + + int FrameIdx = MI.getOperand(i).getIndex(); + unsigned BaseReg = getFrameRegister(MF); + + int Offset = MF.getFrameInfo().getObjectOffset(FrameIdx); + if (!TFI->hasFP(MF)) { + Offset += MF.getFrameInfo().getStackSize(); + } + + // fold imm into offset + Offset += MI.getOperand(i + 1).getImm(); + + // If the MachineInstr is an LEA, expand it to an ADDI_i10 or SUBI_i10 here + if (MI.getOpcode() == AAP::LEA) { + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + unsigned DstReg = MI.getOperand(0).getReg(); + + assert(((Offset >= -1023) || (Offset <= 1023)) && + "Currently LEA immediates must be in the range [-1023, 1023]"); + + if (Offset > 0) { + BuildMI(MBB, &MI, DL, TII->get(AAP::ADDI_i10), DstReg) + .addReg(BaseReg) + .addImm(Offset); + } else if (Offset < 0) { + BuildMI(MBB, &MI, DL, TII->get(AAP::SUBI_i10), DstReg) + .addReg(BaseReg) + .addImm(-Offset); + } else { + BuildMI(MBB, &MI, DL, TII->get(AAP::MOV_r), DstReg).addReg(BaseReg); + } + MI.eraseFromParent(); + } else { + MI.getOperand(i).ChangeToRegister(BaseReg, false); + MI.getOperand(i + 1).ChangeToImmediate(Offset); + } +} + +unsigned AAPRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + + return TFI->hasFP(MF) ? getFramePtrRegister() : getStackPtrRegister(); +} + +unsigned AAPRegisterInfo::getLinkRegister() { return AAP::R0; } +unsigned AAPRegisterInfo::getStackPtrRegister() { return AAP::R1; } +unsigned AAPRegisterInfo::getFramePtrRegister() { return AAP::R2; } Index: lib/Target/AAP/AAPSelectionDAGInfo.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAPSelectionDAGInfo.h @@ -0,0 +1,30 @@ +//===-- AAPSelectionDAGInfo.h - AAP SelectionDAG Info -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AAP subclass for TargetSelectionDAGInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef AAPSELECTIONDAGINFO_H +#define AAPSELECTIONDAGINFO_H + +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" + +namespace llvm { + +class AAPTargetMachine; + +class AAPSelectionDAGInfo : public SelectionDAGTargetInfo { +public: + explicit AAPSelectionDAGInfo(); + ~AAPSelectionDAGInfo(); +}; +} + +#endif Index: lib/Target/AAP/AAPSelectionDAGInfo.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPSelectionDAGInfo.cpp @@ -0,0 +1,20 @@ +//===-- AAPSelectionDAGInfo.cpp - AAP SelectionDAG Info -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the AAPSelectionDAGInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "AAP-selectiondag-info" +#include "AAPTargetMachine.h" +using namespace llvm; + +AAPSelectionDAGInfo::AAPSelectionDAGInfo() : SelectionDAGTargetInfo() {} + +AAPSelectionDAGInfo::~AAPSelectionDAGInfo() {} Index: lib/Target/AAP/AAPSubtarget.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAPSubtarget.h @@ -0,0 +1,67 @@ +//===-- AAPSubtarget.h - Define Subtarget for the AAP -----------*- 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 AAP specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef AAP_SUBTARGET_H +#define AAP_SUBTARGET_H + +#include "AAPFrameLowering.h" +#include "AAPISelLowering.h" +#include "AAPInstrInfo.h" +#include "AAPSelectionDAGInfo.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetSubtargetInfo.h" +#include + +#define GET_SUBTARGETINFO_HEADER +#include "AAPGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class AAPSubtarget : public AAPGenSubtargetInfo { + virtual void anchor(); + AAPInstrInfo InstrInfo; + AAPFrameLowering FrameLowering; + AAPTargetLowering TLInfo; + AAPSelectionDAGInfo TSInfo; + +public: + /// This constructor initializes the data members to match that + /// of the specified triple. + /// + AAPSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS, + const TargetMachine &TM); + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + + const AAPInstrInfo *getInstrInfo() const override { return &InstrInfo; } + const AAPFrameLowering *getFrameLowering() const override { + return &FrameLowering; + } + const AAPTargetLowering *getTargetLowering() const override { + return &TLInfo; + } + const AAPSelectionDAGInfo *getSelectionDAGInfo() const override { + return &TSInfo; + } + const TargetRegisterInfo *getRegisterInfo() const override { + return &InstrInfo.getRegisterInfo(); + } +}; +} // End llvm namespace + +#endif Index: lib/Target/AAP/AAPSubtarget.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPSubtarget.cpp @@ -0,0 +1,32 @@ +//===-- AAPSubtarget.cpp - AAP Subtarget Information ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the AAP specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#include "AAPSubtarget.h" +#include "AAP.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "aap-subtarget" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "AAPGenSubtargetInfo.inc" + +void AAPSubtarget::anchor() {} + +AAPSubtarget::AAPSubtarget(const Triple &TT, const std::string &CPU, + const std::string &FS, const TargetMachine &TM) + : AAPGenSubtargetInfo(TT, CPU, FS), InstrInfo(*this), FrameLowering(), + TLInfo(TM, *this), TSInfo() {} Index: lib/Target/AAP/AAPTargetMachine.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAPTargetMachine.h @@ -0,0 +1,48 @@ +//===-- AAPTargetMachine.h - Define TargetMachine for AAP --------- 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 AAP specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef AAP_TARGETMACHINE_H +#define AAP_TARGETMACHINE_H + +#include "AAPSubtarget.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +class AAPTargetMachine : public LLVMTargetMachine { + std::unique_ptr TLOF; + AAPSubtarget Subtarget; + +public: + AAPTargetMachine(const Target &T, const Triple &TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + Optional RM, CodeModel::Model CM, + CodeGenOpt::Level OL); + ~AAPTargetMachine() override; + + const AAPSubtarget *getSubtargetImpl(const Function &F) const override { + return &Subtarget; + } + + TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + + TargetLoweringObjectFile *getObjFileLowering() const override { + return TLOF.get(); + } +}; // AAPTargetMachine + +} // end namespace llvm + +#endif Index: lib/Target/AAP/AAPTargetMachine.cpp =================================================================== --- lib/Target/AAP/AAPTargetMachine.cpp +++ lib/Target/AAP/AAPTargetMachine.cpp @@ -11,6 +11,60 @@ // //===----------------------------------------------------------------------===// +#include "AAPTargetMachine.h" +#include "MCTargetDesc/AAPMCTargetDesc.h" +#include "llvm/ADT/Triple.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + extern "C" void LLVMInitializeAAPTarget() { + // Register the target + RegisterTargetMachine X(getTheAAPTarget()); +} + +static Reloc::Model getEffectiveRelocModel(Optional RM) { + if (!RM.hasValue()) + return Reloc::Static; + return *RM; +} + +AAPTargetMachine::AAPTargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Optional RM, + CodeModel::Model CM, CodeGenOpt::Level OL) + : LLVMTargetMachine(T, "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-n16", TT, + CPU, FS, Options, getEffectiveRelocModel(RM), CM, OL), + TLOF(make_unique()), + Subtarget(TT, CPU, FS, *this) { + initAsmInfo(); +} + +AAPTargetMachine::~AAPTargetMachine() {} + +namespace { +/// AAP Code Generator Pass Configuration Options. +class AAPPassConfig : public TargetPassConfig { +public: + AAPPassConfig(AAPTargetMachine &TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) {} + + AAPTargetMachine &getAAPTargetMachine() const { + return getTM(); + } + + bool addInstSelector() override; +}; +} // namespace + +TargetPassConfig *AAPTargetMachine::createPassConfig(PassManagerBase &PM) { + return new AAPPassConfig(*this, PM); } +bool AAPPassConfig::addInstSelector() { + addPass(createAAPISelDag(getAAPTargetMachine(), getOptLevel())); + return false; +} Index: lib/Target/AAP/CMakeLists.txt =================================================================== --- lib/Target/AAP/CMakeLists.txt +++ lib/Target/AAP/CMakeLists.txt @@ -6,11 +6,23 @@ tablegen(LLVM AAPGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM AAPGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM AAPGenAsmMatcher.inc -gen-asm-matcher) +tablegen(LLVM AAPGenDAGISel.inc -gen-dag-isel) tablegen(LLVM AAPGenSubtargetInfo.inc -gen-subtarget) +tablegen(LLVM AAPGenCallingConv.inc -gen-callingconv) add_public_tablegen_target(AAPCommonTableGen) add_llvm_target(AAPCodeGen + AAPFrameLowering.cpp + AAPInstrInfo.cpp + AAPISelDAGToDAG.cpp + AAPISelLowering.cpp + AAPMachineFunctionInfo.cpp + AAPRegisterInfo.cpp + AAPSelectionDAGInfo.cpp + AAPSubtarget.cpp AAPTargetMachine.cpp + AAPAsmPrinter.cpp + AAPMCInstLower.cpp ) add_subdirectory(Disassembler) Index: lib/Target/AAP/LLVMBuild.txt =================================================================== --- lib/Target/AAP/LLVMBuild.txt +++ lib/Target/AAP/LLVMBuild.txt @@ -30,5 +30,5 @@ type = Library name = AAPCodeGen parent = AAP -required_libraries = AsmPrinter CodeGen Core MC SelectionDAG Support Target AAPAsmPrinter AAPInfo +required_libraries = AsmPrinter CodeGen Core MC SelectionDAG Support Target AAPAsmPrinter AAPDesc AAPInfo add_to_library_groups = AAP Index: test/CodeGen/AAP/add-sub.ll =================================================================== --- /dev/null +++ test/CodeGen/AAP/add-sub.ll @@ -0,0 +1,100 @@ +; RUN: llc -asm-show-inst -march=aap < %s | FileCheck %s + + +@i16_glob = external global i16 + + +; Simple tests of basic word size add/sub operations + + +; ADD + +define i16 @add_short_imm(i16 %x) { +entry: +;CHECK: add_short_imm: +;CHECK: addi ${{r[0-9]+}}, ${{r[0-9]+}}, 3 {{.*ADDI_i(3|10)}} + %0 = add i16 %x, 3 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @add_imm(i16 %x) { +entry: +;CHECK: add_imm: +;CHECK: addi ${{r[0-9]+}}, ${{r[0-9]+}}, 123 {{.*ADDI_i10}} + %0 = add i16 %x, 123 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @add_big_imm(i16 %x) { +entry: +;CHECK: add_big_imm: +;CHECK: movi ${{r[0-9]+}}, 21345 {{.*MOVI_i16}} +;CHECK: add ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*ADD_r}} + %0 = add i16 %x, 21345 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @add_reg(i16 %x, i16 %y) { +entry: +;CHECK: add_reg: +;CHECK: add ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*ADD_r}} + %0 = add i16 %x, %y + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +; Short adds cannot have a relocation in the immediate +define i16 @add_global(i16 %x) { +entry: +;CHECK: add_global: +;CHECK: movi ${{r[0-9]+}}, i16_glob {{.*MOVI_i16}} +;CHECK: add ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*ADD_r}} + %0 = add i16 %x, ptrtoint (i16* @i16_glob to i16) + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + + +; SUB + +define i16 @sub_short_imm(i16 %x) { +entry: +;CHECK: sub_short_imm: +;CHECK: subi ${{r[0-9]+}}, ${{r[0-9]+}}, 3 {{.*SUBI_i(3|10)}} + %0 = sub i16 %x, 3 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +; TODO: ADD_r is selected instead of SUBI_i10 +define i16 @sub_imm(i16 %x) { +entry: +;CHECK: sub_imm: +;CHECK: subi ${{r[0-9]+}}, ${{r[0-9]+}}, 252 {{.*SUBI_i10}} + %0 = sub i16 %x, 252 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @sub_big_imm(i16 %x) { +entry: +;CHECK: sub_big_imm: +;CHECK: movi ${{r[0-9]+}}, 12345 {{.*MOVI_i16}} +;CHECK: sub ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*SUB_r}} + %0 = sub i16 %x, 12345 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @sub_reg(i16 %x, i16 %y) { +entry: +;CHECK: sub_reg: +;CHECK: sub ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*SUB_r}} + %0 = sub i16 %x, %y + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +; Short subs cannot have a relocation in the immediate +define i16 @sub_global(i16 %x) { +entry: +;CHECK: sub_global: +;CHECK: movi ${{r[0-9]+}}, i16_glob {{.*MOVI_i16}} +;CHECK: sub ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*SUB_r}} + %0 = sub i16 %x, ptrtoint (i16* @i16_glob to i16) + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} Index: test/CodeGen/AAP/lit.local.cfg =================================================================== --- /dev/null +++ test/CodeGen/AAP/lit.local.cfg @@ -0,0 +1,3 @@ +if not 'AAP' in config.root.targets: + config.unsupported = True + Index: test/CodeGen/AAP/load-offset.ll =================================================================== --- /dev/null +++ test/CodeGen/AAP/load-offset.ll @@ -0,0 +1,394 @@ +; RUN: llc -asm-show-inst -march=aap < %s | FileCheck %s + + +; Check the correctness of loads with offsets + + +@i8_array = external global [12345 x i8] +@i16_array = external global [12345 x i16] + +@i8_ptr = external global i8 +@i16_ptr = external global i16 + + +; Byte loads with positive immediate offsets + + +define i8 @ldb_global_zero_imm() { +entry: +;CHECK: ldb_global_zero_imm: +;CHECK: movi $[[REG1:r[0-9]+]], i8_array {{.*MOVI_i16}} +;CHECK: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 0 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +define i8 @ldb_global_short_imm_1() { +entry: +;CHECK: ldb_global_short_imm_1: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i8_array+2 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 2 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is only just small enough to fit in the LDB_short offset. +define i8 @ldb_global_short_imm_2() { +entry: +;CHECK: ldb_global_short_imm_2: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i8_array+3 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 3 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is just too large for the LDB_short offset +define i8 @ldb_global_short_imm_3() { +entry: +;CHECK: ldb_global_short_imm_3: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i8_array+4 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 4 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is too large for the LDB_short offset field, but will still +; fit in the LDB offset. +define i8 @ldb_global_imm_1() { +entry: +;CHECK: ldb_global_imm_1: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i8_array+26 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 26 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is large enough to exceed the signed LDB offset field, +; but small enough to fit in the ADDI_i10 unsigned immediate field. +define i8 @ldb_global_imm_2() { +entry: +;CHECK: ldb_global_imm_2: +;CHECK: movi $[[REG1:r[0-9]+]], i8_array+768 {{.*MOVI_i16}} +;CHECK: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 768 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is too large for the LDB offset field +define i8 @ldb_global_big_imm() { +entry: +;CHECK: ldb_global_big_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i8_array+1234 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 1234 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + + +; Byte load with negative immediate offsets + + +define i8 @ldb_global_short_neg_imm_1() { +entry: +;CHECK: ldb_global_short_neg_imm_1: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i8_array-2 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 -2 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is only just small enough to fit in the LDB_short offset. +define i8 @ldb_global_short_neg_imm_2() { +entry: +;CHECK: ldb_global_short_neg_imm_2: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i8_array-4 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 -4 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is just too large for the LDB_short offset +define i8 @ldb_global_short_neg_imm_3() { +entry: +;CHECK: ldb_global_short_neg_imm_3: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i8_array-5 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 -5 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is too large for the LDB_short offset field, but will still +; fit in the LDB offset. +define i8 @ldb_global_neg_imm_1() { +entry: +;CHECK: ldb_global_neg_imm_1: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i8_array-26 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 -26 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is large enough to exceed the signed LDB offset field, +; but small enough to fit in the SUBI_i10 unsigned immediate field. +define i8 @ldb_global_neg_imm_2() { +entry: +;CHECK: ldb_global_neg_imm_2: +;CHECK: movi $[[REG1:r[0-9]+]], i8_array-755 {{.*MOVI_i16}} +;CHECK: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 -755 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is too large for the LDB offset field +define i8 @ldb_global_big_neg_imm() { +entry: +;CHECK: ldb_global_big_neg_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i8_array-1234 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 -1234 + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + + +; Byte loads from a register with an immediate offset + + +define i8 @ldb_reg_imm(i8* %x) { +entry: +;CHECK: ldb_reg_imm: +;CHECK-DAG: ldb ${{r[0-9]+}}, [${{r[0-9]+}}, 15] {{.*LDB}} + %0 = ptrtoint i8* %x to i16 + %1 = add i16 %0, 15 + %2 = inttoptr i16 %1 to i8* + %3 = load i8, i8* %2 + ret i8 %3 ;CHECK: jmp {{.*JMP}} +} + +define i8 @ldb_reg_big_imm(i8* %x) { +entry: +;CHECK: ldb_reg_big_imm: +;CHECK movi ${{r[0-9]+}}, 12345 {{.*MOVI_i16}} +;CHECK-DAG: add $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*ADD_r}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = ptrtoint i8* %x to i16 + %1 = add i16 %0, 12345 + %2 = inttoptr i16 %1 to i8* + %3 = load i8, i8* %2 + ret i8 %3 ;CHECK: jmp {{.*JMP}} +} + +; With a negative offset +define i8 @ldb_reg_neg_imm(i8* %x) { +entry: +;CHECK: ldb_reg_neg_imm: +;CHECK: ldb ${{r[0-9]+}}, [${{r[0-9]+}}, -432] {{.*LDB$}} + %0 = ptrtoint i8* %x to i16 + %1 = sub i16 %0, 432 + %2 = inttoptr i16 %1 to i8* + %3 = load i8, i8* %2 + ret i8 %3 ;CHECK: jmp {{.*JMP}} +} + + +; Byte loads from a global with a register offset + + +define i8 @ldb_global_reg(i16 %x) { +entry: +;CHECK: ldb_global_reg: +;CHECK-DAG: movi ${{r[0-9]+}}, i8_array {{.*MOVI_i16}} +;CHECK-DAG: add $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*ADD_r}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 %x + %1 = load i8, i8* %0 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +; With a negative register offset +define i8 @ldb_global_neg_reg(i16 %x) { +entry: +;CHECK: ldb_global_neg_reg: +;CHECK: movi ${{r[0-9]+}}, i8_array {{.*MOVI_i16}} +;CHECK-DAG: sub $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*SUB_r}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = sub i16 0, %x + %1 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 %0 + %2 = load i8, i8* %1 + ret i8 %2 ;CHECK: jmp {{.*JMP}} +} + + +; Byte loads from a global with a global offset +define i8 @ldb_global_global() { +entry: +;CHECK: ldb_global_global: +;CHECK-DAG: movi ${{r[0-9]+}}, i8_array {{.*MOVI_i16}} +;CHECK-DAG: movi ${{r[0-9]+}}, i8_ptr {{.*MOVI_i16}} +;CHECK-DAG: add $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*ADD_r}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = ptrtoint i8* @i8_ptr to i16 + %1 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 %0 + %2 = load i8, i8* %1 + ret i8 %2 ;CHECK: jmp {{.*JMP}} +} + +define i8 @ldb_global_neg_global() { +entry: +;CHECK: ldb_global_neg_global: +;CHECK-DAG: movi ${{r[0-9]+}}, i8_array {{.*MOVI_i16}} +;CHECK-DAG: movi ${{r[0-9]+}}, i8_ptr {{.*MOVI_i16}} +;CHECK-DAG: sub $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*SUB_r}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = ptrtoint i8* @i8_ptr to i16 + %1 = sub i16 0, %0 + %2 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 %1 + %3 = load i8, i8* %2 + ret i8 %3 ;CHECK: jmp {{.*JMP}} +} + + +; Word loads with positive immediate offsets + + +define i16 @ldw_global_zero_imm() { +entry: +;CHECK: ldw_global_zero_imm: +;CHECK: movi $[[REG1:r[0-9]+]], i16_array {{.*MOVI_i16}} +;CHECK: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = getelementptr [12345 x i16], [12345 x i16]* @i16_array, i16 0, i16 0 + %1 = load i16, i16* %0 + ret i16 %1 ;CHECK: jmp {{.*JMP}} +} + +define i16 @ldw_global_short_imm() { +entry: +;CHECK: ldw_global_short_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i16_array+2 {{.*MOVI_i16}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = getelementptr [12345 x i16], [12345 x i16]* @i16_array, i16 0, i16 1 + %1 = load i16, i16* %0 + ret i16 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is too large for the LDW_short offset field, but will still +; fit in the LDW offset. +define i16 @ldw_global_imm() { +entry: +;CHECK: ldw_global_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i16_array+424 {{.*MOVI_i16}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = getelementptr [12345 x i16], [12345 x i16]* @i16_array, i16 0, i16 212 + %1 = load i16, i16* %0 + ret i16 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is too large for the LDB offset field +define i16 @ldw_global_big_imm() { +entry: +;CHECK: ldw_global_big_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i16_array+2468 {{.*MOVI_i16}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = getelementptr [12345 x i16], [12345 x i16]* @i16_array, i16 0, i16 1234 + %1 = load i16, i16* %0 + ret i16 %1 ;CHECK: jmp {{.*JMP}} +} + + +; Word load with negative immediate offsets + + +define i16 @ldw_global_short_neg_imm() { +entry: +;CHECK: ldw_global_short_neg_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], i16_array-4 {{.*MOVI_i16}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = getelementptr [12345 x i16], [12345 x i16]* @i16_array, i16 0, i16 -2 + %1 = load i16, i16* %0 + ret i16 %1 ;CHECK: jmp {{.*JMP}} +} + +; The immediate is large enough to exceed the signed LDW offset field, +; but small enough to fit in the SUBI_i10 unsigned immediate field. +define i16 @ldw_global_neg_imm() { +entry: +;CHECK: ldw_global_neg_imm: +;CHECK: movi $[[REG1:r[0-9]+]], i16_array-634 {{.*MOVI_i16}} +;CHECK: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = getelementptr [12345 x i16], [12345 x i16]* @i16_array, i16 0, i16 -317 + %1 = load i16, i16* %0 + ret i16 %1 ;CHECK: jmp {{.*JMP}} +} + + +; Word loads from a register with an immediate offset + + +define i16 @ldw_reg_imm(i16* %x) { +entry: +;CHECK: ldw_reg_imm: +;CHECK-DAG: ldw ${{r[0-9]+}}, [${{r[0-9]+}}, 16] {{.*LDW}} + %0 = ptrtoint i16* %x to i16 + %1 = add i16 %0, 16 + %2 = inttoptr i16 %1 to i16* + %3 = load i16, i16* %2 + ret i16 %3 ;CHECK: jmp {{.*JMP}} +} + +define i16 @ldw_reg_big_neg_imm(i16* %x) { +entry: +;CHECK: ldw_reg_big_neg_imm: +;CHECK movi ${{r[0-9]+}}, 22222 {{.*MOVI_i16}} +;CHECK-DAG: sub $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*SUB_r}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = ptrtoint i16* %x to i16 + %1 = sub i16 %0, 22222 + %2 = inttoptr i16 %1 to i16* + %3 = load i16, i16* %2 + ret i16 %3 ;CHECK: jmp {{.*JMP}} +} + + +; Byte loads from a global with a register offset + + +define i16 @ldw_global_reg(i16 %x) { +entry: +;CHECK: ldw_global_reg: +;CHECK-DAG: movi ${{r[0-9]+}}, i16_array {{.*MOVI_i16}} +;CHECK-DAG: add $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*ADD_r}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = getelementptr [12345 x i16], [12345 x i16]* @i16_array, i16 0, i16 %x + %1 = load i16, i16* %0 + ret i16 %1 ;CHECK: jmp {{.*JMP}} +} + + +; Byte loads from a global with a global offset + + +define i16 @ldw_global_neg_global() { +entry: +;CHECK: ldw_global_neg_global: +;CHECK-DAG: movi ${{r[0-9]+}}, i16_array {{.*MOVI_i16}} +;CHECK-DAG: movi ${{r[0-9]+}}, i16_ptr {{.*MOVI_i16}} +;CHECK-DAG: sub $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*SUB_r}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = ptrtoint i16* @i16_ptr to i16 + %1 = sub i16 0, %0 + %2 = getelementptr [12345 x i16], [12345 x i16]* @i16_array, i16 0, i16 %1 + %3 = load i16, i16* %2 + ret i16 %3 ;CHECK: jmp {{.*JMP}} +} Index: test/CodeGen/AAP/load.ll =================================================================== --- /dev/null +++ test/CodeGen/AAP/load.ll @@ -0,0 +1,69 @@ +; RUN: llc -asm-show-inst -march=aap < %s | FileCheck %s + + +; Check the correctness of various simple load operations. + + +@a = external global i16 +@b = external global i16 + +@c = external global i8 +@d = external global i8 + + +define i8 @ldb_global() { +entry: +;CHECK: ldb_global: +;CHECK: movi $[[REG1:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = load i8, i8* @c, align 1 + ret i8 %0 ;CHECK: jmp {{.*JMP}} +} + +define i8 @ldb_imm() { +entry: +;CHECK: ldb_imm: +;CHECK: movi $[[REG1:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB}} + %0 = inttoptr i16 123 to i8* + %1 = load i8, i8* %0, align 1 + ret i8 %1 ;CHECK: jmp {{.*JMP}} +} + +define i8 @ldb_reg(i8* %x) { +entry: +;CHECK: ldb_reg: +;CHECK: ldb ${{r[0-9]+}}, [${{r[0-9]+}}, 0] {{.*LDB}} + %0 = load i8, i8* %x, align 1 + ret i8 %0 ;CHECK: jmp {{.*JMP}} +} + + + + +define i16 @ldw_global() { +entry: +;CHECK: ldw_global: +;CHECK: movi $[[REG1:r[0-9]+]], a {{.*MOVI_i16}} +;CHECK: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = load i16, i16* @a, align 2 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @ldw_imm() { +entry: +;CHECK: ldw_imm: +;CHECK: movi $[[REG1:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW}} + %0 = inttoptr i16 123 to i16* + %1 = load i16, i16* %0, align 2 + ret i16 %1 ;CHECK: jmp {{.*JMP}} +} + +define i16 @ldw_reg(i16* %x) { +entry: +;CHECK: ldw_reg: +;CHECK: ldw ${{r[0-9]+}}, [${{r[0-9]+}}, 0] {{.*LDW}} + %0 = load i16, i16* %x, align 2 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} Index: test/CodeGen/AAP/logical.ll =================================================================== --- /dev/null +++ test/CodeGen/AAP/logical.ll @@ -0,0 +1,64 @@ +; RUN: llc -asm-show-inst -march=aap < %s | FileCheck %s + + +; Simple tests of basic word size logical operations + + +; AND + +define i16 @and_imm(i16 %x) { +entry: +;CHECK: and_imm: +;CHECK: andi ${{r[0-9]+}}, ${{r[0-9]+}}, 3 {{.*ANDI_i9}} + %0 = and i16 %x, 3 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @and_big_imm(i16 %x) { +entry: +;CHECK: and_big_imm: +;CHECK: movi ${{r[0-9]+}}, 19283 {{.*MOVI_i16}} +;CHECK: and ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*AND_r}} + %0 = and i16 %x, 19283 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + + +; OR + +define i16 @or_imm(i16 %x) { +entry: +;CHECK: or_imm: +;CHECK: ori ${{r[0-9]+}}, ${{r[0-9]+}}, 3 {{.*ORI_i9}} + %0 = or i16 %x, 3 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @or_big_imm(i16 %x) { +entry: +;CHECK: or_big_imm: +;CHECK: movi ${{r[0-9]+}}, 19283 {{.*MOVI_i16}} +;CHECK: or ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*OR_r}} + %0 = or i16 %x, 19283 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + + +; XOR + +define i16 @xor_imm(i16 %x) { +entry: +;CHECK: xor_imm: +;CHECK: xori ${{r[0-9]+}}, ${{r[0-9]+}}, 3 {{.*XORI_i9}} + %0 = xor i16 %x, 3 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @xor_big_imm(i16 %x) { +entry: +;CHECK: xor_big_imm: +;CHECK: movi ${{r[0-9]+}}, 19283 {{.*MOVI_i16}} +;CHECK: xor ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*XOR_r}} + %0 = xor i16 %x, 19283 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} Index: test/CodeGen/AAP/shift.ll =================================================================== --- /dev/null +++ test/CodeGen/AAP/shift.ll @@ -0,0 +1,85 @@ +; RUN: llc -asm-show-inst -march=aap < %s | FileCheck %s + + +; Simple tests of basic word size shift operations + + +; ASR + +define i16 @asr_small_imm(i16 %x) { +entry: +;CHECK: asr_small_imm: +;CHECK: asri ${{r[0-9]+}}, ${{r[0-9]+}}, 3 {{.*ASRI_i(3|6)}} + %0 = ashr i16 %x, 3 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @asr_imm(i16 %x) { +entry: +;CHECK: asr_imm: +;CHECK: asri ${{r[0-9]+}}, ${{r[0-9]+}}, 14 {{.*ASRI_i6}} + %0 = ashr i16 %x, 14 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @asr_reg(i16 %x, i16 %y) { +entry: +;CHECK: asr_reg: +;CHECK: asr ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*ASR_r}} + %0 = ashr i16 %x, %y + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + + +; LSL + +define i16 @lsl_small_imm(i16 %x) { +entry: +;CHECK: lsl_small_imm: +;CHECK: lsli ${{r[0-9]+}}, ${{r[0-9]+}}, 3 {{.*LSLI_i(3|6)}} + %0 = shl i16 %x, 3 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @lsl_imm(i16 %x) { +entry: +;CHECK: lsl_imm: +;CHECK: lsli ${{r[0-9]+}}, ${{r[0-9]+}}, 14 {{.*LSLI_i6}} + %0 = shl i16 %x, 14 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @lsl_reg(i16 %x, i16 %y) { +entry: +;CHECK: lsl_reg: +;CHECK: lsl ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*LSL_r}} + %0 = shl i16 %x, %y + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + + +; LSR + +define i16 @lsr_small_imm(i16 %x) { +entry: +;CHECK: lsr_small_imm: +;CHECK: lsri ${{r[0-9]+}}, ${{r[0-9]+}}, 3 {{.*LSRI_i(3|6)}} + %0 = lshr i16 %x, 3 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @lsr_imm(i16 %x) { +entry: +;CHECK: lsr_imm: +;CHECK: lsri ${{r[0-9]+}}, ${{r[0-9]+}}, 14 {{.*LSRI_i6}} + %0 = lshr i16 %x, 14 + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} + +define i16 @lsr_reg(i16 %x, i16 %y) { +entry: +;CHECK: lsr_reg: +;CHECK: lsr ${{r[0-9]+}}, ${{r[0-9]+}}, ${{r[0-9]+}} {{.*LSR_r}} + %0 = lshr i16 %x, %y + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} Index: test/CodeGen/AAP/store-offset.ll =================================================================== --- /dev/null +++ test/CodeGen/AAP/store-offset.ll @@ -0,0 +1,104 @@ +; RUN: llc -asm-show-inst -march=aap < %s | FileCheck %s + + +; Check the correctness of stores with offsets + + +@i8_array = external global [12345 x i8] +@i16_array = external global [12345 x i16] + +@i8_ptr = external global i8 +@i16_ptr = external global i16 + + +; Byte stores with positive immediate offsets + + +define void @stb_global_zero_imm_offset_imm() { +entry: +;CHECK: stb_global_zero_imm_offset_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], i8_array {{.*MOVI_i16}} +;CHECK-DAG: stb [$[[REG2]], 0], $[[REG1]] {{.*STB(_short)?}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 0 + store i8 123, i8* %0 + ret void ;CHECK jmp {{.*JMP}} +} + +define void @stb_global_short_imm_offset_imm() { +entry: +;CHECK: stb_global_short_imm_offset_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], i8_array+3 {{.*MOVI_i16}} +;CHECK-DAG: stb [$[[REG2]], 0], $[[REG1]] {{.*STB(_short)?}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 3 + store i8 123, i8* %0 + ret void ;CHECK jmp {{.*JMP}} +} + +define void @stb_global_imm_offset_imm() { +entry: +;CHECK: stb_global_imm_offset_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], i8_array+4 {{.*MOVI_i16}} +;CHECK-DAG: stb [$[[REG2]], 0], $[[REG1]] {{.*STB(_short)?}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 4 + store i8 123, i8* %0 + ret void ;CHECK jmp {{.*JMP}} +} + + +; Byte stores with negative immediate offsets + + +define void @stb_global_neg_imm_offset_imm() { +entry: +;CHECK: stb_global_neg_imm_offset_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], i8_array+511 {{.*MOVI_i16}} +;CHECK-DAG: stb [$[[REG2]], 0], $[[REG1]] {{.*STB(_short)?}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 511 + store i8 123, i8* %0 + ret void ;CHECK jmp {{.*JMP}} +} + +define void @stb_global_big_neg_imm_offset_imm() { +entry: +;CHECK: stb_global_big_neg_imm_offset_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK-DAG: movi ${{r[0-9]+}}, i8_array-513 {{.*MOVI_i16}} +;CHECK-DAG: stb [$[[REG2]], 0], $[[REG1]] {{.*STB(_short)?}} + %0 = getelementptr [12345 x i8], [12345 x i8]* @i8_array, i16 0, i16 -513 + store i8 123, i8* %0 + ret void ;CHECK jmp {{.*JMP}} +} + + +; Word stores to a register with an immediate offset + + +define void @stw_reg_short_imm_offset_imm(i16* %x) { +entry: +;CHECK: stw_reg_short_imm_offset_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 12345 {{.*MOVI_i16}} +;CHECK-DAG: stw [${{r[0-9]+}}, 2], $[[REG1]] {{.*STW(_short)?}} + %0 = ptrtoint i16* %x to i16 + %1 = add i16 %0, 2 + %2 = inttoptr i16 %1 to i16* + store i16 12345, i16* %2 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stw_reg_big_neg_imm_offset_imm(i16* %x) { +entry: +;CHECK: stw_reg_big_neg_imm_offset_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 17291 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], 9280 {{.*MOVI_i16}} +;CHECK-DAG: sub $[[REG3:r[0-9]+]], ${{r[0-9]+}}, $[[REG2]] {{.*SUB_r(_short)?}} +;CHECK-DAG: stw [$[[REG3]], 0], $[[REG1]] {{.*STW(_short)?}} + %0 = ptrtoint i16* %x to i16 + %1 = sub i16 %0, 9280 + %2 = inttoptr i16 %1 to i16* + store i16 17291, i16* %2 + ret void ;CHECK jmp {{.*JMP}} +} Index: test/CodeGen/AAP/store.ll =================================================================== --- /dev/null +++ test/CodeGen/AAP/store.ll @@ -0,0 +1,195 @@ +; RUN: llc -asm-show-inst -march=aap < %s | FileCheck %s + + +; Check the correctness of various simple store operations. + + +@a = external global i16 +@b = external global i16 + +@c = external global i8 +@d = external global i8 + + +define void @stb_global_global() { +entry: +;CHECK: stb_global_global: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], d {{.*MOVI_i16}} +;CHECK: stb [$[[REG1]], 0], $[[REG2]] {{.*STB}} + %0 = ptrtoint i8* @d to i8 + store i8 %0, i8* @c, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stb_global_imm() { +entry: +;CHECK: stb_global_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK: stb [$[[REG1]], 0], $[[REG2]] {{.*STB}} + store i8 123, i8* @c, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stb_global_reg(i8 %x) { +entry: +;CHECK: stb_global_reg: +;CHECK: movi $[[REG1:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK: stb [$[[REG1]], 0], ${{r[0-9]+}} {{.*STB}} + store i8 %x, i8* @c, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stb_imm_global() { +entry: +;CHECK: stb_imm_global: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 345 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK: stb [$[[REG1]], 0], $[[REG2]] {{.*STB}} + %0 = inttoptr i16 345 to i8* + %1 = ptrtoint i8* @c to i8 + store i8 %1, i8* %0, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stb_imm_imm() { +entry: +;CHECK: stb_imm_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 456 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK: stb [$[[REG1]], 0], $[[REG2]] {{.*STB}} + %0 = inttoptr i16 456 to i8* + store i8 123, i8* %0, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stb_imm_reg(i8 %x) { +entry: +;CHECK: stb_imm_reg: +;CHECK: movi $[[REG1:r[0-9]+]], 345 {{.*MOVI_i16}} +;CHECK: stb [$[[REG1]], 0], ${{r[0-9]+}} {{.*STB}} + %0 = inttoptr i16 345 to i8* + store i8 %x, i8* %0, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stb_reg_global(i8 *%x) { +entry: +;CHECK: stb_reg_global: +;CHECK: movi $[[REG1:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK: stb [${{r[0-9]+}}, 0], $[[REG1]] {{.*STB}} + %0 = ptrtoint i8* @c to i8 + store i8 %0, i8* %x, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stb_reg_imm(i8* %x) { +entry: +;CHECK: stb_reg_imm: +;CHECK: movi $[[REG1:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK: stb [${{r[0-9]+}}, 0], $[[REG1]] {{.*STB}} + store i8 123, i8* %x, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stb_reg_reg(i8* %x, i8 %y) { +entry: +;CHECK: stb_reg_reg: +;CHECK: stb [${{r[0-9]+}}, 0], ${{r[0-9]+}} {{.*STB}} + store i8 %y, i8* %x, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + + + + +define void @stw_global_global() { +entry: +;CHECK: stw_global_global: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], a {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], b {{.*MOVI_i16}} +;CHECK: stw [$[[REG1]], 0], $[[REG2]] {{.*STW}} + %0 = ptrtoint i16* @b to i16 + store i16 %0, i16* @a, align 2 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stw_global_imm() { +entry: +;CHECK: stw_global_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], a {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK: stw [$[[REG1]], 0], $[[REG2]] {{.*STW}} + store i16 123, i16* @a, align 2 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stw_global_reg(i16 %x) { +entry: +;CHECK: stw_global_reg: +;CHECK: movi $[[REG1:r[0-9]+]], a {{.*MOVI_i16}} +;CHECK: stw [$[[REG1]], 0], ${{r[0-9]+}} {{.*STW}} + store i16 %x, i16* @a, align 2 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stw_imm_global() { +entry: +;CHECK: stw_imm_global: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 345 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], a {{.*MOVI_i16}} +;CHECK: stw [$[[REG1]], 0], $[[REG2]] {{.*STW}} + %0 = inttoptr i16 345 to i16* + %1 = ptrtoint i16* @a to i16 + store i16 %1, i16* %0, align 2 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stw_imm_imm() { +entry: +;CHECK: stw_imm_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 456 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK: stw [$[[REG1]], 0], $[[REG2]] {{.*STW}} + %0 = inttoptr i16 456 to i16* + store i16 123, i16* %0, align 2 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stw_imm_reg(i16 %x) { +entry: +;CHECK: stw_imm_reg: +;CHECK: movi $[[REG1:r[0-9]+]], 345 {{.*MOVI_i16}} +;CHECK: stw [$[[REG1]], 0], ${{r[0-9]+}} {{.*STW}} + %0 = inttoptr i16 345 to i16* + store i16 %x, i16* %0, align 2 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stw_reg_global(i16 *%x) { +entry: +;CHECK: stw_reg_global: +;CHECK: movi $[[REG1:r[0-9]+]], a {{.*MOVI_i16}} +;CHECK: stw [${{r[0-9]+}}, 0], $[[REG1]] {{.*STW}} + %0 = ptrtoint i16* @a to i16 + store i16 %0, i16* %x, align 2 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stw_reg_imm(i16* %x) { +entry: +;CHECK: stw_reg_imm: +;CHECK: movi $[[REG1:r[0-9]+]], 123 {{.*MOVI_i16}} +;CHECK: stw [${{r[0-9]+}}, 0], $[[REG1]] {{.*STW}} + store i16 123, i16* %x, align 2 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @stw_reg_reg(i16* %x, i16 %y) { +entry: +;CHECK: stw_reg_reg: +;CHECK: stw [${{r[0-9]+}}, 0], ${{r[0-9]+}} {{.*STW}} + store i16 %y, i16* %x, align 2 + ret void ;CHECK: jmp {{.*JMP}} +} Index: test/CodeGen/AAP/truncstore.ll =================================================================== --- /dev/null +++ test/CodeGen/AAP/truncstore.ll @@ -0,0 +1,108 @@ +; RUN: llc -asm-show-inst -march=aap < %s | FileCheck %s + + +; Check the correctness of truncstore operations in codegen. + + +@c = external global i8 +@d = external global i8 + + +define void @truncstore_i16_i8_global_global() { +entry: +;CHECK: truncstore_i16_i8_global_global: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], d {{.*MOVI_i16}} +;CHECK: stb [$[[REG2]], 0], $[[REG1]] {{.*STB}} + %0 = ptrtoint i8* @c to i16 + %1 = trunc i16 %0 to i8 + store i8 %1, i8* @d, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @truncstore_i16_i8_global_imm() { +entry: +;CHECK: truncstore_i16_i8_global_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 210 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK: stb [$[[REG2]], 0], $[[REG1]] {{.*STB}} + %0 = trunc i16 1234 to i8 + store i8 %0, i8* @c, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @truncstore_i16_i8_global_reg(i16 %x) { +entry: +;CHECK: truncstore_i16_i8_global_reg: +;CHECK: movi $[[REG2:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK: stb [$[[REG2]], 0], ${{r[0-9]+}} {{.*STB}} + %0 = trunc i16 %x to i8 + store i8 %0, i8* @c, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @truncstore_i16_i8_imm_global() { +entry: +;CHECK: truncstore_i16_i8_imm_global: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], 1234 {{.*MOVI_i16}} +;CHECK: stb [$[[REG2]], 0], $[[REG1]] {{.*STB}} + %0 = ptrtoint i8* @c to i16 + %1 = trunc i16 %0 to i8 + %2 = inttoptr i16 1234 to i8* + store i8 %1, i8* %2, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @truncstore_i16_i8_imm_imm() { +entry: +;CHECK: truncstore_i16_i8_imm_imm: +;CHECK-DAG: movi $[[REG1:r[0-9]+]], 215 {{.*MOVI_i16}} +;CHECK-DAG: movi $[[REG2:r[0-9]+]], 1234 {{.*MOVI_i16}} +;CHECK: stb [$[[REG2]], 0], $[[REG1]] {{.*STB}} + %0 = trunc i16 4567 to i8 + %1 = inttoptr i16 1234 to i8* + store i8 %0, i8* %1, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @truncstore_i16_i8_imm_reg(i16 %x) { +entry: +;CHECK: truncstore_i16_i8_imm_reg: +;CHECK: movi $[[REG1:r[0-9]+]], 1234 {{.*MOVI_i16}} +;CHECK: stb [$[[REG1]], 0], ${{r[0-9]+}} {{.*STB}} + %0 = trunc i16 %x to i8 + %1 = inttoptr i16 1234 to i8* + store i8 %0, i8* %1, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @truncstore_i16_i8_reg_global(i8* %x) { +entry: +;CHECK: truncstore_i16_i8_reg_global: +;CHECK: movi $[[REG1:r[0-9]+]], c {{.*MOVI_i16}} +;CHECK: stb [${{r[0-9]+}}, 0], $[[REG1]] {{.*STB}} + %0 = ptrtoint i8* @c to i16 + %1 = trunc i16 %0 to i8 + store i8 %1, i8* %x, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @truncstore_i16_i8_reg_imm(i8* %x) { +entry: +;CHECK: truncstore_i16_i8_reg_imm: +;CHECK: movi $[[REG1:r[0-9]+]], 215 {{.*MOVI_i16}} +;CHECK: stb [${{r[0-9]+}}, 0], $[[REG1]] {{.*STB}} + %0 = trunc i16 4567 to i8 + store i8 %0, i8* %x, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} + +define void @truncstore_i16_i8_reg_reg(i8* %x, i16 %y) { +entry: +;CHECK: truncstore_i16_i8_reg_reg: +;CHECK: stb [${{r[0-9]+}}, 0], ${{r[0-9]+}} {{.*STB}} + %0 = trunc i16 %y to i8 + store i8 %0, i8* %x, align 1 + ret void ;CHECK: jmp {{.*JMP}} +}