Index: bindings/python/llvm/disassembler.py =================================================================== --- bindings/python/llvm/disassembler.py +++ bindings/python/llvm/disassembler.py @@ -36,7 +36,7 @@ _initialized = False -_targets = ['AArch64', 'ARM', 'Hexagon', 'MSP430', 'Mips', 'NVPTX', 'PowerPC', 'R600', 'Sparc', 'SystemZ', 'X86', 'XCore'] +_targets = ['AArch64', 'ARM', 'Hexagon', 'MSP430', 'Mips', 'NVPTX', 'PowerPC', 'R600', 'Sparc', 'SystemZ', 'AAP', 'X86', 'XCore'] def _ensure_initialized(): global _initialized if not _initialized: Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -376,6 +376,8 @@ set(LLVM_NATIVE_ARCH WebAssembly) elseif (LLVM_NATIVE_ARCH MATCHES "wasm64") set(LLVM_NATIVE_ARCH WebAssembly) +elseif (LLVM_NATIVE_ARCH MATCHES "aap") + set(LLVM_NATIVE_ARCH AAP) else () message(FATAL_ERROR "Unknown architecture ${LLVM_NATIVE_ARCH}") endif () Index: include/llvm/ADT/Triple.h =================================================================== --- include/llvm/ADT/Triple.h +++ include/llvm/ADT/Triple.h @@ -89,7 +89,8 @@ lanai, // Lanai: Lanai 32-bit wasm32, // WebAssembly with 32-bit pointers wasm64, // WebAssembly with 64-bit pointers - LastArchType = wasm64 + aap, // AAP architecture + LastArchType = aap }; enum SubArchType { NoSubArch, Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -166,7 +166,7 @@ const DataLayout &getDataLayout() const; /// Return the pointer size from the TargetMachine - unsigned getPointerSize() const; + virtual unsigned getPointerSize() const; /// Return information about subtarget. const MCSubtargetInfo &getSubtargetInfo() const; Index: include/llvm/CodeGen/MachineRegisterInfo.h =================================================================== --- include/llvm/CodeGen/MachineRegisterInfo.h +++ include/llvm/CodeGen/MachineRegisterInfo.h @@ -123,6 +123,10 @@ /// second element. std::vector > LiveIns; + /// Keep track of the physical registers that are live out of the function. + /// Live out values are return values in registers. + std::vector LiveOuts; + MachineRegisterInfo(const MachineRegisterInfo&) = delete; void operator=(const MachineRegisterInfo&) = delete; public: @@ -746,6 +750,12 @@ LiveIns.push_back(std::make_pair(Reg, vreg)); } + /// addLiveOut - Add the specified register as a live-out. Note that it + /// is an error to add the same register to the same set more than once. + void addLiveOut(unsigned Reg) { + LiveOuts.push_back(Reg); + } + // Iteration support for the live-ins set. It's kept in sorted order // by register number. typedef std::vector >::const_iterator @@ -756,6 +766,14 @@ bool isLiveIn(unsigned Reg) const; + // Iteration support for the live-outs set. Not necessarily in sorted order. + typedef std::vector::const_iterator liveout_iterator; + liveout_iterator liveout_begin() const { return LiveOuts.begin(); } + liveout_iterator liveout_end() const { return LiveOuts.end(); } + bool liveout_empty() const { return LiveOuts.empty(); } + + bool isLiveOut(unsigned Reg) const; + /// getLiveInPhysReg - If VReg is a live-in virtual register, return the /// corresponding live-in physical register. unsigned getLiveInPhysReg(unsigned VReg) const; Index: include/llvm/Object/ELFObjectFile.h =================================================================== --- include/llvm/Object/ELFObjectFile.h +++ include/llvm/Object/ELFObjectFile.h @@ -838,6 +838,8 @@ return "ELF32-wasm"; case ELF::EM_AMDGPU: return "ELF32-amdgpu"; + case ELF::EM_AAP: + return "ELF32-aap"; default: return "ELF32-unknown"; } Index: include/llvm/Support/ELF.h =================================================================== --- include/llvm/Support/ELF.h +++ include/llvm/Support/ELF.h @@ -320,6 +320,8 @@ // an official value for Lanai. As soon as one is allocated, this enum will be // updated to use it. EM_LANAI = 0x8123, // Lanai 32-bit processor + + EM_AAP = 0x5343 // AAP }; // Object file classes. @@ -614,6 +616,11 @@ #include "ELFRelocs/WebAssembly.def" }; +// ELF Relocation type for AAP. +enum { +#include "ELFRelocs/AAP.def" +}; + #undef ELF_RELOC // Section header. Index: include/llvm/Support/ELFRelocs/AAP.def =================================================================== --- /dev/null +++ include/llvm/Support/ELFRelocs/AAP.def @@ -0,0 +1,23 @@ + +#ifndef ELF_RELOC +#error "ELF_RELOC must be defined" +#endif + +ELF_RELOC(R_AAP_NONE, 0x00) +ELF_RELOC(R_AAP_8, 0x01) +ELF_RELOC(R_AAP_16, 0x02) +ELF_RELOC(R_AAP_32, 0x03) +ELF_RELOC(R_AAP_64, 0x04) +ELF_RELOC(R_AAP_BR16, 0x05) +ELF_RELOC(R_AAP_BR32, 0x06) +ELF_RELOC(R_AAP_BRCC16, 0x07) +ELF_RELOC(R_AAP_BRCC32, 0x08) +ELF_RELOC(R_AAP_BAL16, 0x09) +ELF_RELOC(R_AAP_BAL32, 0x0a) +ELF_RELOC(R_AAP_ABS6, 0x0b) +ELF_RELOC(R_AAP_ABS9, 0x0c) +ELF_RELOC(R_AAP_ABS10, 0x0d) +ELF_RELOC(R_AAP_ABS12, 0x0e) +ELF_RELOC(R_AAP_ABS16, 0x0f) +ELF_RELOC(R_AAP_OFF10, 0x10) +ELF_RELOC(R_AAP_SHIFT6, 0x11) Index: include/llvm/module.modulemap =================================================================== --- include/llvm/module.modulemap +++ include/llvm/module.modulemap @@ -196,6 +196,7 @@ // These are intended for textual inclusion. textual header "Support/ARMTargetParser.def" textual header "Support/Dwarf.def" + textual header "Support/ELFRelocs/AAP.def" textual header "Support/ELFRelocs/AArch64.def" textual header "Support/ELFRelocs/ARM.def" textual header "Support/ELFRelocs/AVR.def" Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -141,7 +141,12 @@ // Do not use the cached DataLayout because some client use it without a Module // (llmv-dsymutil, llvm-dwarfdump). -unsigned AsmPrinter::getPointerSize() const { return TM.getPointerSize(); } +// By default, use the pointer size defined by the target machine +unsigned AsmPrinter::getPointerSize() const { + if (MAI) + return MAI->getPointerSize(); + return TM.getPointerSize(); +} const MCSubtargetInfo &AsmPrinter::getSubtargetInfo() const { assert(MF && "getSubtargetInfo requires a valid MachineFunction!"); Index: lib/CodeGen/MachineRegisterInfo.cpp =================================================================== --- lib/CodeGen/MachineRegisterInfo.cpp +++ lib/CodeGen/MachineRegisterInfo.cpp @@ -370,6 +370,13 @@ return false; } +bool MachineRegisterInfo::isLiveOut(unsigned Reg) const { + for (liveout_iterator I = liveout_begin(), E = liveout_end(); I != E; ++I) + if (*I == Reg) + return true; + return false; +} + /// getLiveInPhysReg - If VReg is a live-in virtual register, return the /// corresponding live-in physical register. unsigned MachineRegisterInfo::getLiveInPhysReg(unsigned VReg) const { Index: lib/CodeGen/TargetFrameLoweringImpl.cpp =================================================================== --- lib/CodeGen/TargetFrameLoweringImpl.cpp +++ lib/CodeGen/TargetFrameLoweringImpl.cpp @@ -81,6 +81,14 @@ if (CallsUnwindInit || MRI.isPhysRegModified(Reg)) SavedRegs.set(Reg); } + + // Don't save any register which is live out of the function + for (unsigned i = 0; CSRegs[i]; ++i) { + unsigned Reg = CSRegs[i]; + if (MRI.isLiveOut(Reg)) { + SavedRegs.reset(Reg); + } + } } unsigned TargetFrameLowering::getStackAlignmentSkew( Index: lib/Object/ELF.cpp =================================================================== --- lib/Object/ELF.cpp +++ lib/Object/ELF.cpp @@ -40,6 +40,13 @@ break; } break; + case ELF::EM_AAP: + switch (Type) { +#include "llvm/Support/ELFRelocs/AAP.def" + default: + break; + } + break; case ELF::EM_AARCH64: switch (Type) { #include "llvm/Support/ELFRelocs/AArch64.def" Index: lib/ObjectYAML/ELFYAML.cpp =================================================================== --- lib/ObjectYAML/ELFYAML.cpp +++ lib/ObjectYAML/ELFYAML.cpp @@ -530,6 +530,9 @@ break; case ELF::EM_LANAI: #include "llvm/Support/ELFRelocs/Lanai.def" + break; + case ELF::EM_AAP: +#include "llvm/Support/ELFRelocs/AAP.def" break; default: llvm_unreachable("Unsupported architecture"); Index: lib/Support/Triple.cpp =================================================================== --- lib/Support/Triple.cpp +++ lib/Support/Triple.cpp @@ -64,6 +64,7 @@ case shave: return "shave"; case wasm32: return "wasm32"; case wasm64: return "wasm64"; + case aap: return "aap"; } llvm_unreachable("Invalid ArchType!"); @@ -131,6 +132,7 @@ case shave: return "shave"; case wasm32: case wasm64: return "wasm"; + case aap: return "aap"; } } @@ -277,6 +279,7 @@ .Case("shave", shave) .Case("wasm32", wasm32) .Case("wasm64", wasm64) + .Case("aap", aap) .Default(UnknownArch); } @@ -386,6 +389,7 @@ .Case("shave", Triple::shave) .Case("wasm32", Triple::wasm32) .Case("wasm64", Triple::wasm64) + .Case("aap", Triple::aap) .Default(Triple::UnknownArch); // Some architectures require special parsing logic just to compute the @@ -564,6 +568,7 @@ return Triple::COFF; return Triple::ELF; + case Triple::aap: case Triple::aarch64_be: case Triple::amdgcn: case Triple::amdil: @@ -1104,6 +1109,7 @@ case llvm::Triple::avr: case llvm::Triple::msp430: + case llvm::Triple::aap: return 16; case llvm::Triple::arm: @@ -1175,6 +1181,7 @@ case Triple::bpfel: case Triple::bpfeb: case Triple::msp430: + case Triple::aap: case Triple::systemz: case Triple::ppc64le: T.setArch(UnknownArch); @@ -1237,6 +1244,7 @@ case Triple::xcore: case Triple::sparcel: case Triple::shave: + case Triple::aap: T.setArch(UnknownArch); break; @@ -1303,6 +1311,7 @@ case Triple::spir: case Triple::wasm32: case Triple::wasm64: + case Triple::aap: case Triple::x86: case Triple::x86_64: case Triple::xcore: @@ -1384,6 +1393,7 @@ case Triple::thumb: case Triple::wasm32: case Triple::wasm64: + case Triple::aap: case Triple::x86: case Triple::x86_64: case Triple::xcore: Index: lib/Target/AAP/AAP.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAP.h @@ -0,0 +1,67 @@ +//===-- AAP.h - Top-level interface for AAP representation ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the entry points for global functions defined in the LLVM +// AAP back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef TARGET_AAP_H +#define TARGET_AAP_H + +#include "MCTargetDesc/AAPMCTargetDesc.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Target/TargetMachine.h" + +namespace AAPCC { +// AAP specific condition codes +enum CondCode { + COND_EQ = 0, + COND_NE = 1, + COND_LTS = 2, + COND_LES = 3, + COND_LTU = 4, + COND_LEU = 5, + COND_INVALID = -1 +}; +} // end namespace AAP + +namespace llvm { +extern Target TheAAPTarget; +class AAPTargetMachine; + +FunctionPass *createAAPISelDag(AAPTargetMachine &TM, + CodeGenOpt::Level OptLevel); + +FunctionPass *createAAPShortInstrPeepholePass(AAPTargetMachine &TM); + +namespace AAP { +// Various helper methods to define operand ranges used throughout the backend +static bool inline isImm3(int64_t I) { return isUInt<3>(I); } +static bool inline isImm6(int64_t I) { return isUInt<6>(I); } +static bool inline isImm9(int64_t I) { return isUInt<9>(I); } +static bool inline isImm10(int64_t I) { return isUInt<10>(I); } +static bool inline isImm12(int64_t I) { return isUInt<12>(I); } + +static bool inline isOff3(int64_t I) { return isInt<3>(I); } +static bool inline isOff6(int64_t I) { return isInt<6>(I); } +static bool inline isOff9(int64_t I) { return isInt<9>(I); } +static bool inline isOff10(int64_t I) { return isInt<10>(I); } + +static bool inline isField16(int64_t I) { + return isInt<16>(I) || isUInt<16>(I); +} + +static bool inline isShiftImm3(int64_t I) { return (I >= 1) && (I <= 8); } +static bool inline isShiftImm6(int64_t I) { return (I >= 1) && (I <= 64); } + +} // end of namespace AAP +} // end namespace llvm + +#endif Index: lib/Target/AAP/AAP.td =================================================================== --- /dev/null +++ lib/Target/AAP/AAP.td @@ -0,0 +1,47 @@ +//===- AAP.td - Describe the AAP Target Machine ------------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces which we are implementing +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// AAP Subtarget features. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// AAP processors supported. +//===----------------------------------------------------------------------===// + +class Proc Features> + : Processor; + +def : Proc<"generic", []>; + + +//===----------------------------------------------------------------------===// +// Register File, Calling Conv, Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "AAPRegisterInfo.td" +include "AAPCallingConv.td" +include "AAPInstrFormats.td" +include "AAPInstrInfo.td" + +def AAPInstrInfo : InstrInfo; + +//===----------------------------------------------------------------------===// +// Declare the target which we are implementing +//===----------------------------------------------------------------------===// + +def AAP : Target { + let InstructionSet = AAPInstrInfo; +} Index: lib/Target/AAP/AAPAsmPrinter.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPAsmPrinter.cpp @@ -0,0 +1,98 @@ +//===-- 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 "AAP.h" +#include "InstPrinter/AAPInstPrinter.h" +#include "AAPInstrInfo.h" +#include "AAPMCInstLower.h" +#include "AAPTargetMachine.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)) {} + + const char *getPassName() const override { return "AAP Assembly Printer"; } + + void printOperand(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; + + 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; + } + } +} + +bool AAPAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O) { + printOperand(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(TheAAPTarget); +} 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; + + void + 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,131 @@ +//===-- 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 "AAP.h" +#include "AAPInstrInfo.h" +#include "AAPMachineFunctionInfo.h" +#include "AAPSubtarget.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 +void AAPFrameLowering::eliminateCallFramePseudoInstr( + MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + assert(!hasFP(MF) && "Frame pointer unsupported!"); + 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,205 @@ +//===-- 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 "AAP.h" +#include "AAPMachineFunctionInfo.h" +#include "AAPRegisterInfo.h" +#include "AAPSubtarget.h" +#include "AAPTargetMachine.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 const char *getPassName() const override { + return "AAP DAG->DAG Pattern Instruction Selection"; + } + +// 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); + } + + SDNode *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 + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +SDNode *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 NULL; + } + + /// + // 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 + return CurDAG->getMachineNode(AAP::LEA, dl, MVT::i16, TFI, + CurDAG->getTargetConstant(0, dl, MVT::i16)); + } + default: + break; + } + + // Select the default instruction + SDNode *ResNode = SelectCode(Node); + + DEBUG(errs() << "=> "); + if (ResNode == NULL || ResNode == Node) + DEBUG(Node->dump(CurDAG)); + else + DEBUG(ResNode->dump(CurDAG)); + DEBUG(errs() << "\n"); + return ResNode; +} + +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,148 @@ +//===-- 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; + +private: + SDValue LowerGlobalAddress(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, + 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, SDLoc dl, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerCCCArguments(SDValue Chain, CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, SDLoc dl, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, SDLoc dl, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, 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,830 @@ +//===-- 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 "AAP.h" +#include "AAPMachineFunctionInfo.h" +#include "AAPRegisterInfo.h" +#include "AAPSubtarget.h" +#include "AAPTargetMachine.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::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); + + // Custom DAGCombine operations + 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::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"); +} + +// 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; + } +} + +// Map the generic BR_CC instruction to a specific branch instruction based on +// the provided AAP condition code. This always maps to a long instruction. +static unsigned getBranchOpForCondition(AAPCC::CondCode CC) { + switch (CC) { + 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_; + default: + llvm_unreachable("Unknown condition code!"); + return 0; + } +} + +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), false, false, 0); +} + +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(); + + // Create the TargetGlobalAddress node, folding in the constant offset. + SDValue Result = + DAG.getTargetGlobalAddress(GV, SDLoc(Op), getPointerTy(DL), Offset); + 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, 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, 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.getSimpleVT().SimpleTy << "\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), false, + false, false, 0); + } + + InVals.push_back(InVal); + } + } + + return Chain; +} + +SDValue +AAPTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + 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)); + + // Mark return registers as live-out in MachineRegisterInfo + MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo(); + for (unsigned i = 0; i != RVLocs.size(); ++i) { + MRI.addLiveOut(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, 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, DAG.getConstant(NumBytes, DL, getPointerTy(TD), true), 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(), + false, false, 0); + } + + 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 + const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); + const uint32_t *Mask = + TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv); + assert(Mask && "No call preserved mask for the calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + + 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); +} + +/// 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, SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) 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)); + } + + 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 &TII = *MBB->getParent()->getSubtarget().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 = getBranchOpForCondition(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 &TII = *MBB->getParent()->getSubtarget().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 = getBranchOpForCondition(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/AAPInstrFormats.td =================================================================== --- /dev/null +++ lib/Target/AAP/AAPInstrFormats.td @@ -0,0 +1,282 @@ +//===- AAPInstrFormats.td - AAP Instruction Formats ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// Instruction Format Superclasses +//===----------------------------------------------------------------------===// + +class InstAAP_base opclass, dag outs, dag ins, + string asmstr, list pattern> + : Instruction { + let Namespace = "AAP"; + + dag OutOperandList = outs; + dag InOperandList = ins; + let AsmString = asmstr; + let Pattern = pattern; + + let Size = 4; + field bits<32> Inst; + field bits<32> SoftFail = 0; + + let Inst{31} = 0; + let Inst{15} = 1; + let Inst{14-13} = opclass{1-0}; + let Inst{30-29} = opclass{3-2}; +} + + +class InstAAP opclass, bits<8> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_base { + let Inst{12-9} = opcode{3-0}; + let Inst{28-25} = opcode{7-4}; +} + + +class InstAAP_short opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : Instruction { + let Namespace = "AAP"; + + dag OutOperandList = outs; + dag InOperandList = ins; + let AsmString = asmstr; + let Pattern = pattern; + + let Size = 2; + field bits<16> Inst; + field bits<16> SoftFail = 0; + + let Inst{15} = 0; + let Inst{14-13} = opclass; + let Inst{12-9} = opcode; +} + + +//===----------------------------------------------------------------------===// +// Instruction Formats +//===----------------------------------------------------------------------===// + +class Inst_rrr opclass, bits<8> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP { + bits<6> rD; + bits<6> rA; + bits<6> rB; + let Inst{8-6} = rD{2-0}; + let Inst{24-22} = rD{5-3}; + let Inst{5-3} = rA{2-0}; + let Inst{21-19} = rA{5-3}; + let Inst{2-0} = rB{2-0}; + let Inst{18-16} = rB{5-3}; +} +class Inst_rrr_short opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_short { + bits<3> rD; + bits<3> rA; + bits<3> rB; + let Inst{8-6} = rD; + let Inst{5-3} = rA; + let Inst{2-0} = rB; +} + + +class Inst_r opclass, bits<8> opcode, dag outs, dag ins, + string asmstr, list pattern> + : Inst_rrr { + let rA = 0; + let rB = 0; +} +class Inst_r_short opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : Inst_rrr_short { + let rA = 0; + let rB = 0; +} + + +class Inst_rr_i6 opclass, bits<8> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP { + bits<6> rD; + bits<6> rA; + bits<6> imm; + let Inst{8-6} = rD{2-0}; + let Inst{24-22} = rD{5-3}; + let Inst{5-3} = rA{2-0}; + let Inst{21-19} = rA{5-3}; + let Inst{2-0} = imm{2-0}; + let Inst{18-16} = imm{5-3}; +} +class Inst_rr_i3_short opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_short { + bits<3> rD; + bits<3> rA; + bits<3> imm; + let Inst{8-6} = rD; + let Inst{5-3} = rA; + let Inst{2-0} = imm; +} + + +class Inst_rr_i9 opclass, bits<5> opcode, dag outs, dag ins, + string asmstr, listpattern> + : InstAAP_base { + bits<6> rD; + bits<6> rA; + bits<9> imm; + + let Inst{12-9} = opcode{3-0}; // Define low bits of the opcode field + let Inst{25} = opcode{4}; + + let Inst{8-6} = rD{2-0}; + let Inst{24-22} = rD{5-3}; + let Inst{5-3} = rA{2-0}; + let Inst{21-19} = rA{5-3}; + let Inst{2-0} = imm{2-0}; + let Inst{18-16} = imm{5-3}; + let Inst{28-26} = imm{8-6}; // Immediate reuses high bits of opcode field +} +class Inst_rr_i10 opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_base { + bits<6> rD; + bits<6> rA; + bits<10> imm; + + let Inst{12-9} = opcode; // Define low bits of the opcode field + + let Inst{8-6} = rD{2-0}; + let Inst{24-22} = rD{5-3}; + let Inst{5-3} = rA{2-0}; + let Inst{21-19} = rA{5-3}; + let Inst{2-0} = imm{2-0}; + let Inst{18-16} = imm{5-3}; + let Inst{28-25} = imm{9-6}; // Immediate reuses high bits of opcode field +} + + +class Inst_r_i12 opclass, bits<8> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP { + bits<6> rD; + bits<12> imm; + + let Inst{8-6} = rD{2-0}; + let Inst{24-22} = rD{5-3}; + let Inst{5-0} = imm{5-0}; + let Inst{21-16} = imm{11-6}; +} +class Inst_r_i6_short opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_short { + bits<3> rD; + bits<6> imm; + let Inst{8-6} = rD; + let Inst{5-0} = imm; +} + + +class Inst_r_i16 opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_base { + bits<6> rD; + bits<16> imm; + + let Inst{12-9} = opcode; // Define low bits of the opcode field + + let Inst{8-6} = rD{2-0}; + let Inst{24-22} = rD{5-3}; + let Inst{5-0} = imm{5-0}; + let Inst{21-16} = imm{11-6}; + let Inst{28-25} = imm{15-12}; // Imm reuses high bits of opcode field +} + + +class Inst_i22 opclass, bits<8> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP { + bits<22> imm; + let Inst{8-0} = imm{8-0}; + let Inst{28-16} = imm{21-9}; +} +class Inst_i9_short opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_short { + bits<9> imm; + let Inst{8-0} = imm; +} + + +class Inst_i16_r opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_base { + bits<16> imm; + bits<6> rB; + + let Inst{12-9} = opcode; // Define low bits of opcode field + + let Inst{8-3} = imm{5-0}; + let Inst{28-19} = imm{15-6}; // Reuse opcode high bits + + let Inst{2-0} = rB{2-0}; + let Inst{18-16} = rB{5-3}; +} +class Inst_i6_r_short opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_short { + bits<6> imm; + bits<3> rB; + let Inst{2-0} = rB{2-0}; + let Inst{8-3} = imm{5-0}; +} + + +class Inst_i10_rr opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_base { + bits<10> imm; + bits<6> rA; + bits<6> rB; + + let Inst{12-9} = opcode; // Define low bits of opcode field + + let Inst{8-6} = imm{2-0}; + let Inst{28-22} = imm{9-3}; // Reuse top bits of opcode field + let Inst{5-3} = rA{2-0}; + let Inst{21-19} = rA{5-3}; + let Inst{2-0} = rB{2-0}; + let Inst{18-16} = rB{5-3}; +} +class Inst_i3_rr_short opclass, bits<4> opcode, dag outs, dag ins, + string asmstr, list pattern> + : InstAAP_short { + bits<3> imm; + bits<3> rA; + bits<3> rB; + let Inst{8-6} = imm; + let Inst{5-3} = rA; + let Inst{2-0} = rB; +} + + +//===----------------------------------------------------------------------===// +// Pseudo Instruction +//===----------------------------------------------------------------------===// + +let isCodeGenOnly = 1 in { +class Pseudo pattern> + : InstAAP<0x0, 0x0, outs, ins, asmstr, pattern> { + let Inst{31-0} = 0; +} +} Index: lib/Target/AAP/AAPInstrInfo.h =================================================================== --- /dev/null +++ lib/Target/AAP/AAPInstrInfo.h @@ -0,0 +1,67 @@ +//===-- 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 "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; } + + bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const override; + + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef Cond, + DebugLoc DL) const override; + + unsigned RemoveBranch(MachineBasicBlock &MBB) const override; + + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + 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,131 @@ +//===-- 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 "AAP.h" +#include "AAPMachineFunctionInfo.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 +//===----------------------------------------------------------------------===// + +bool AAPInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const { + return true; +} + +unsigned AAPInstrInfo::InsertBranch(MachineBasicBlock &MBB, + MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + ArrayRef Cond, + DebugLoc DL) const { + return 0; +} + +unsigned AAPInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { return 0; } + +void AAPInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, 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/AAPInstrInfo.td =================================================================== --- /dev/null +++ lib/Target/AAP/AAPInstrInfo.td @@ -0,0 +1,636 @@ +//===-- AAPInstrInfo.td - Target Description 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 describes the AAP instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +// Call +def sdt_call : SDTypeProfile<0, -1, [SDTCisVT<1, iPTR>, SDTCisVT<1, i16>]>; +def sdt_ret : SDTypeProfile<0, 1, [SDTCisVT<0, i16>]>; +def callflag : SDNode<"AAPISD::CALL", sdt_call, + [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; +def retflag : SDNode<"AAPISD::RET_FLAG", sdt_ret, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; +def sdt_callseqstart : SDCallSeqStart<[SDTCisVT<0, i16>]>; +def sdt_callseqend : SDCallSeqEnd<[SDTCisVT<0, i16>, SDTCisVT<1, i16>]>; +def callseq_start : SDNode<"ISD::CALLSEQ_START", sdt_callseqstart, + [SDNPHasChain, SDNPOutGlue]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", sdt_callseqend, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; +def sdt_wrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, + SDTCisPtrTy<0>]>; +def aapwrapper : SDNode<"AAPISD::Wrapper", sdt_wrapper>; + +def sdt_selectcc : SDTypeProfile<1, 5, [SDTCisSameAs<0, 3>, + SDTCisSameAs<1, 2>, + SDTCisSameAs<3, 4>, + SDTCisVT<5, i16>]>; +def sdt_brcc : SDTypeProfile<0, 4, [SDTCisVT<0, i16>, + SDTCisSameAs<1, 2>, + SDTCisVT<3, OtherVT>]>; +def AAPselectcc : SDNode<"AAPISD::SELECT_CC", sdt_selectcc>; +def AAPbrcc : SDNode<"AAPISD::BR_CC", sdt_brcc, + [SDNPHasChain]>; + + +// Branch Operands +def brtarget : Operand { + let PrintMethod = "printPCRelImmOperand"; + let EncoderMethod = "encodePCRelImmOperand"; +} + + +// Immediate operands. Smaller operands are subclasses of larger ones so they +// are correctly prioritized when disassembling. +// +// Currently we have no custom 'signed' immediates, but it will likely +// be needed in the future to handle branches properly. +// +// A constant immediate is an immediate which cannot be an expression, only +// an absolute value. +let RenderMethod = "addImmOperands" in { + def field16AsmOperand : AsmOperandClass { + let Name = "Field16"; let SuperClasses = [ImmAsmOperand]; + } + def imm12AsmOperand : AsmOperandClass { + let Name = "Imm12"; let SuperClasses = [field16AsmOperand]; + } + def imm10AsmOperand : AsmOperandClass { + let Name = "Imm10"; let SuperClasses = [imm12AsmOperand]; + } + def imm9AsmOperand : AsmOperandClass { + let Name = "Imm9"; let SuperClasses = [imm10AsmOperand]; + } + def const6AsmOperand : AsmOperandClass { + let Name = "Const6"; let SuperClasses = [imm9AsmOperand]; + } + def imm6AsmOperand : AsmOperandClass { + let Name = "Imm6"; let SuperClasses = [const6AsmOperand]; + } + def const3AsmOperand : AsmOperandClass { + let Name = "Const3"; let SuperClasses = [imm6AsmOperand]; + } + + // Offsets are signed immediates used for load and store operands + def off10AsmOperand : AsmOperandClass { + let Name = "Off10"; let SuperClasses = [ImmAsmOperand]; + } + def off3AsmOperand : AsmOperandClass { + let Name = "Off3"; let SuperClasses = [off10AsmOperand]; + } + + // Shift operands are unsigned immediates or constants who range + // begins at 1, rather than 0. The encoding is done with the shift amount + // -1. + def shiftImm6AsmOperand : AsmOperandClass { + let Name = "ShiftImm6"; let SuperClasses = [imm9AsmOperand]; + } + def shiftConst3AsmOperand : AsmOperandClass { + let Name = "ShiftConst3"; let SuperClasses = [shiftImm6AsmOperand]; + } +} + +// The various AAP functions called in ImmLeaf here are defined in AAP.h +def field16 : Operand, ImmLeaf { + let EncoderMethod = "encodeField16"; + let ParserMatchClass = field16AsmOperand; +} +def imm12 : Operand, ImmLeaf { + let EncoderMethod = "encodeImm12"; + let ParserMatchClass = imm12AsmOperand; +} +def imm10 : Operand, ImmLeaf { + let EncoderMethod = "encodeImm10"; + let ParserMatchClass = imm10AsmOperand; +} +def imm9 : Operand, ImmLeaf { + let EncoderMethod = "encodeImm9"; + let ParserMatchClass = imm9AsmOperand; +} +def const6 : Operand, ImmLeaf { + let EncoderMethod = "encodeImm6"; + let ParserMatchClass = const6AsmOperand; +} +def imm6 : Operand, ImmLeaf { + let EncoderMethod = "encodeImm6"; + let ParserMatchClass = imm6AsmOperand; +} +def const3 : Operand, ImmLeaf { + let EncoderMethod = "encodeImm3"; + let ParserMatchClass = const3AsmOperand; +} + +// Offset operands +def off10 : Operand, ImmLeaf { + let EncoderMethod = "encodeOff10"; + let ParserMatchClass = off10AsmOperand; +} +def off3 : Operand, ImmLeaf { + let EncoderMethod = "encodeOff3"; + let ParserMatchClass = off3AsmOperand; +} + +// Shift operands, these have custom encoding/decoding to handle the bias +// applied to the value. +def shift_imm6 : Operand, ImmLeaf { + let EncoderMethod = "encodeShiftImm6"; + let DecoderMethod = "decodeShiftOperand"; + let ParserMatchClass = shiftImm6AsmOperand; +} +def shift_const3 : Operand, ImmLeaf { + let EncoderMethod = "encodeShiftConst3"; + let DecoderMethod = "decodeShiftOperand"; + let ParserMatchClass = shiftConst3AsmOperand; +} + + +// Memory offsets consist of a 3 or 10 bit offset and a register operand +def addr_MO3 : ComplexPattern; +def addr_MO10 : ComplexPattern; + + +// Memsrc operand encodings consist of a 16-bit immediate field in the low +// bits, and a 3 or 6 bit register field in the high bits. The encoding +// is exactly the same for predecrement and postincrement address mode. +// +// We enforce a total order between all of the memsrc operand classes using +// SuperClasses so that the shortest instruction is always picked first during +// assembly matching. Load and store instructions have identical mnemonics, +// and therefore their ordering is based on their operand classes. +def memsrc10AsmOperand : AsmOperandClass { + let Name = "MemSrc10"; +} +def memsrc10PostIncAsmOperand : AsmOperandClass { + let Name = "MemSrc10PostInc"; + let SuperClasses = [memsrc10AsmOperand]; +} +def memsrc10PreDecAsmOperand : AsmOperandClass { + let Name = "MemSrc10PreDec"; + let SuperClasses = [memsrc10PostIncAsmOperand]; +} + +def memsrc3AsmOperand : AsmOperandClass { + let Name = "MemSrc3"; + let SuperClasses = [memsrc10PreDecAsmOperand]; +} +def memsrc3PostIncAsmOperand : AsmOperandClass { + let Name = "MemSrc3PostInc"; + let SuperClasses = [memsrc3AsmOperand]; +} +def memsrc3PreDecAsmOperand : AsmOperandClass { + let Name = "MemSrc3PreDec"; + let SuperClasses = [memsrc3PostIncAsmOperand]; +} + +let EncoderMethod = "encodeMemSrcOperand", + DecoderMethod = "decodeMemSrcOperand" in { + def memsrc10 : Operand { + let PrintMethod = "printMemSrcOperand"; + let ParserMatchClass = memsrc10AsmOperand; + let MIOperandInfo = (ops GR64, off10); + } + def memsrc10_postinc : Operand { + let PrintMethod = "printMemSrcPostIncOperand"; + let ParserMatchClass = memsrc10PostIncAsmOperand; + let MIOperandInfo = (ops GR64, off10); + } + def memsrc10_predec : Operand { + let PrintMethod = "printMemSrcPreDecOperand"; + let ParserMatchClass = memsrc10PreDecAsmOperand; + let MIOperandInfo = (ops GR64, off10); + } + def memsrc3 : Operand { + let PrintMethod = "printMemSrcOperand"; + let ParserMatchClass = memsrc3AsmOperand; + let MIOperandInfo = (ops GR8, off3); + } + def memsrc3_postinc : Operand { + let PrintMethod = "printMemSrcPostIncOperand"; + let ParserMatchClass = memsrc3PostIncAsmOperand; + let MIOperandInfo = (ops GR8, off3); + } + def memsrc3_predec : Operand { + let PrintMethod = "printMemSrcPreDecOperand"; + let ParserMatchClass = memsrc3PreDecAsmOperand; + let MIOperandInfo = (ops GR8, off3); + } +} + + +//===----------------------------------------------------------------------===// +// MOV Operations +//===----------------------------------------------------------------------===// + +// May be exapanded to MOV_r_short in peephole pass +def MOV_r : Inst_rrr + <0x0, 0x9, (outs GR64:$rD), (ins GR64:$rA), "mov\t$rD, $rA", []> { + let rB = 0; +} +def MOV_r_short : Inst_rrr_short + <0x0, 0x9, (outs GR8:$rD), (ins GR8:$rA), "mov\t$rD, $rA", []> { + let rB = 0; +} + +// May expand to MOVI_i6_short in peephole pass +def MOVI_i16 : Inst_r_i16 + <0x0, 0xf, (outs GR64:$rD), (ins field16:$imm), "movi\t$rD, $imm", + [(set GR64:$rD, (i16 field16:$imm))]>; +def MOVI_i6_short : Inst_r_i6_short + <0x0, 0xf, (outs GR8:$rD), (ins const6:$imm), "movi\t$rD, $imm", []>; + + +//===----------------------------------------------------------------------===// +// ALU/Logical Operations +//===----------------------------------------------------------------------===// + +// May expand to NOP_short in peephole +def NOP : Inst_r_i12 + <0x0, 0x0, (outs), (ins GR64:$rD, imm12:$imm), "nop\t$rD, $imm", []>; +def NOP_short : Inst_r_i6_short + <0x0, 0x0, (outs), (ins GR8:$rD, const6:$imm), "nop\t$rD, $imm", []>; + + +// ALU ops with register operands +multiclass ALU_r opcode, string opname, SDNode OpNode> { + // May expand to ALU_r_short in peephole + def _r : Inst_rrr + <0x0, opcode, (outs GR64:$rD), (ins GR64:$rA, GR64:$rB), + !strconcat(opname, "\t$rD, $rA, $rB"), + [(set GR64:$rD, (OpNode GR64:$rA, GR64:$rB))]>; + def _r_short : Inst_rrr_short + <0x0, opcode{3-0}, (outs GR8:$rD), (ins GR8:$rA, GR8:$rB), + !strconcat(opname, "\t$rD, $rA, $rB"), []>; +} + + +let isCommutable = 1 in { +let Defs = [PSW] in + defm ADD : ALU_r<0x1, "add", add>; +defm AND : ALU_r<0x3, "and", and>; +defm OR : ALU_r<0x4, "or", or>; +defm XOR : ALU_r<0x5, "xor", xor>; +} + +let Defs = [PSW] in + defm SUB : ALU_r<0x2, "sub", sub>; +defm ASR : ALU_r<0x6, "asr", sra>; +defm LSL : ALU_r<0x7, "lsl", shl>; +defm LSR : ALU_r<0x8, "lsr", srl>; + + +let Uses = [PSW], Defs = [PSW] in { +def ADDC_r : Inst_rrr + <0x0, 0x11, (outs GR64:$rD), (ins GR64:$rA, GR64:$rB), + "addc\t$rD, $rA, $rB", + [(set GR64:$rD, (adde GR64:$rA, GR64:$rB))]>; + +def SUBC_r : Inst_rrr + <0x0, 0x12, (outs GR64:$rD), (ins GR64:$rA, GR64:$rB), + "subc\t$rD, $rA, $rB", + [(set GR64:$rD, (sube GR64:$rA, GR64:$rB))]>; +} + + +// ALU ops with immediates +let Defs = [PSW] in { + +// LEA Pseudo operation, expanded to ADD_i10 or SUB_i10 during frame index +// elimination depending on the sign of the immediate. +def LEA : Pseudo<(outs GR64:$rD), (ins GR64:$rA, i16imm:$imm), "#LEA", []>; + +// Select over MOVI_i16 + ADD_r +// May expand to ADDI_i3_short in peephole +let AddedComplexity = 1 in { + def ADDI_i10 : Inst_rr_i10 + <0x0, 0xa, (outs GR64:$rD), (ins GR64:$rA, imm10:$imm), + "addi\t$rD, $rA, $imm", + [(set GR64:$rD, (add GR64:$rA, (i16 imm10:$imm)))]>; +} +def ADDI_i3_short : Inst_rr_i3_short + <0x0, 0xa, (outs GR8:$rD), (ins GR8:$rA, const3:$imm), + "addi\t$rD, $rA, $imm", []>; + +// Select over MOVI_i16 + SUB_r +// May expand to SUBI_i3_short in peephole +let AddedComplexity = 1 in { + def SUBI_i10 : Inst_rr_i10 + <0x0, 0xb, (outs GR64:$rD), (ins GR64:$rA, imm10:$imm), + "subi\t$rD, $rA, $imm", + [(set GR64:$rD, (sub GR64:$rA, (i16 imm10:$imm)))]>; +} +def SUBI_i3_short : Inst_rr_i3_short + <0x0, 0xb, (outs GR8:$rD), (ins GR8:$rA, const3:$imm), + "subi\t$rD, $rA, $imm", []>; + +} // end of Defs + + +multiclass SHIFT_i opcode, string opname, SDNode OpNode> { + // Select over MOVI_i16 + SHIFT_r + // May expand to SHIFT_i3_short in peephole + let AddedComplexity = 1 in { + def _i6 : Inst_rr_i6 + <0x0, opcode, (outs GR64:$rD), (ins GR64:$rA, shift_imm6:$imm), + !strconcat(opname, "\t$rD, $rA, $imm"), + [(set GR64:$rD, (OpNode GR64:$rA, (i16 shift_imm6:$imm)))]>; + } + def _i3_short : Inst_rr_i3_short + <0x0, opcode{3-0}, (outs GR8:$rD), (ins GR8:$rA, shift_const3:$imm), + !strconcat(opname, "\t$rD, $rA, $imm"), []>; +} +defm ASRI : SHIFT_i<0xc, "asri", sra>; +defm LSLI : SHIFT_i<0xd, "lsli", shl>; +defm LSRI : SHIFT_i<0xe, "lsri", srl>; + + +// Logical operations with immediate +// Select over MOVI_i16 + LOG_r +let AddedComplexity = 1 in { +class LOG_i9 opcode, string opname, SDNode OpNode> + : Inst_rr_i9 + <0x0, opcode, (outs GR64:$rD), (ins GR64:$rA, imm9:$imm), + !strconcat(opname, "\t$rD, $rA, $imm"), + [(set GR64:$rD, (OpNode GR64:$rA, (i16 imm9:$imm)))]>; +} // end of AddedComplexity + +def ANDI_i9 : LOG_i9<0x13, "andi", and>; +def ORI_i9 : LOG_i9<0x14, "ori", or>; +def XORI_i9 : LOG_i9<0x15, "xori", xor>; + + +//===----------------------------------------------------------------------===// +// Load/Store Operations +//===----------------------------------------------------------------------===// + +// TODO: It may be better for the LOAD/STORE classes to be in the formats .td +// TODO: There's quite a lot of duplication here as the Load/Store classes +// end up defining a lot of the fields themselves. + +class LOAD opcode, string opname, dag outs, dag ins> + : InstAAP + <0x1, opcode, outs, ins, !strconcat(opname, "\t$rD, [$src]"), []> { + bits<6> rD; + bits<22> src; // 6-bit reg field, 16 bit imm field + + let Inst{8-6} = rD{2-0}; + let Inst{24-22} = rD{5-3}; + + let Inst{5-3} = src{18-16}; + let Inst{21-19} = src{21-19}; + let Inst{2-0} = src{2-0}; + let Inst{18-16} = src{5-3}; + let Inst{28-25} = src{9-6}; // reuse second word opcode field for offset +} + +class LOAD_short opcode, string opname, dag outs, dag ins> + : InstAAP_short + <0x1, opcode, outs, ins, !strconcat(opname, "\t$rD, [$src]"), []> { + bits<3> rD; + bits<19> src; // 3-bit reg field, 16 bit imm field + + let Inst{8-6} = rD; + let Inst{5-3} = src{18-16}; + let Inst{2-0} = src{2-0}; +} + +class STORE opcode, string opname, dag outs, dag ins> + : InstAAP + <0x1, opcode, outs, ins, !strconcat(opname, "\t[$dst], $rA"), []> { + bits<22> dst; // 6-bit reg field, 16 bit imm field + bits<6> rA; + + let Inst{8-6} = dst{18-16}; + let Inst{24-22} = dst{21-19}; + let Inst{2-0} = dst{2-0}; + let Inst{18-16} = dst{5-3}; + let Inst{28-25} = dst{9-6}; // reuse second word opcode field for offset + + let Inst{5-3} = rA{2-0}; + let Inst{21-19} = rA{5-3}; +} + +class STORE_short opcode, string opname, dag outs, dag ins> + : InstAAP_short + <0x1, opcode, outs, ins, !strconcat(opname, "\t[$dst], $rA"), []> { + bits<19> dst; // 3-bit reg field, 16 bit imm field + bits<3> rA; + + let Inst{8-6} = dst{18-16}; + let Inst{2-0} = dst{2-0}; + let Inst{5-3} = rA; +} + + +// Short load/store instructions use the memsrc3 operand type, which uses a +// different fixup when encoding and a different matching class when parsing +// assembly. + +// Load instruction may expand to short equivalents in peephole +let mayLoad = 1 in { +def LDB : LOAD<0x0, "ldb", (outs GR64:$rD), (ins memsrc10:$src)>; +def LDW : LOAD<0x4, "ldw", (outs GR64:$rD), (ins memsrc10:$src)>; +def LDB_postinc : LOAD<0x1, "ldb", (outs GR64:$rD), (ins memsrc10_postinc:$src)>; +def LDW_postinc : LOAD<0x5, "ldw", (outs GR64:$rD), (ins memsrc10_postinc:$src)>; +def LDB_predec : LOAD<0x2, "ldb", (outs GR64:$rD), (ins memsrc10_predec:$src)>; +def LDW_predec : LOAD<0x6, "ldw", (outs GR64:$rD), (ins memsrc10_predec:$src)>; +} // end of mayLoad + +let mayLoad = 1 in { +def LDB_short : LOAD_short<0x0, "ldb", (outs GR8:$rD), (ins memsrc3:$src)>; +def LDW_short : LOAD_short<0x4, "ldw", (outs GR8:$rD), (ins memsrc3:$src)>; +def LDB_postinc_short : LOAD_short<0x1, "ldb", (outs GR8:$rD), (ins memsrc3_postinc:$src)>; +def LDW_postinc_short : LOAD_short<0x5, "ldw", (outs GR8:$rD), (ins memsrc3_postinc:$src)>; +def LDB_predec_short : LOAD_short<0x2, "ldb", (outs GR8:$rD), (ins memsrc3_predec:$src)>; +def LDW_predec_short : LOAD_short<0x6, "ldw", (outs GR8:$rD), (ins memsrc3_predec:$src)>; +} // end of mayLoad + +// Load patterns +def : Pat<(i16 (zextloadi8 GR64:$src)), (LDB GR64:$src, (i16 0))>; +def : Pat<(i16 (zextloadi8 addr_MO10:$src)), (LDB addr_MO10:$src)>; + +def : Pat<(i16 (extloadi8 GR64:$src)), (LDB GR64:$src, (i16 0))>; +def : Pat<(i16 (extloadi8 addr_MO10:$src)), (LDB addr_MO10:$src)>; + +def : Pat<(i16 (load GR64:$src)), (LDW GR64:$src, (i16 0))>; +def : Pat<(i16 (load addr_MO10:$src)), (LDW addr_MO10:$src)>; + + +// Store instruction may expand to short equivalents in peephole +let mayStore = 1 in { +def STB : STORE<0x8, "stb", (outs), (ins memsrc10:$dst, GR64:$rA)>; +def STW : STORE<0xc, "stw", (outs), (ins memsrc10:$dst, GR64:$rA)>; +def STB_postinc : STORE<0x9, "stb", (outs), (ins memsrc10_postinc:$dst, GR64:$rA)>; +def STW_postinc : STORE<0xd, "stw", (outs), (ins memsrc10_postinc:$dst, GR64:$rA)>; +def STB_predec : STORE<0xa, "stb", (outs), (ins memsrc10_predec:$dst, GR64:$rA)>; +def STW_predec : STORE<0xe, "stw", (outs), (ins memsrc10_predec:$dst, GR64:$rA)>; +} // end of mayStore + +let mayStore = 1 in { +def STB_short : STORE_short<0x8, "stb", (outs), (ins memsrc3:$dst, GR8:$rA)>; +def STW_short : STORE_short<0xc, "stw", (outs), (ins memsrc3:$dst, GR8:$rA)>; +def STB_postinc_short : STORE_short<0x9, "stb", (outs), (ins memsrc3_postinc:$dst, GR8:$rA)>; +def STW_postinc_short : STORE_short<0xd, "stw", (outs), (ins memsrc3_postinc:$dst, GR8:$rA)>; +def STB_predec_short : STORE_short<0xa, "stb", (outs), (ins memsrc3_predec:$dst, GR8:$rA)>; +def STW_predec_short : STORE_short<0xe, "stw", (outs), (ins memsrc3_predec:$dst, GR8:$rA)>; +} // end of mayStore + +// Store patterns +def : Pat<(truncstorei8 GR64:$src, GR64:$dst), (STB GR64:$dst, (i16 0), GR64:$src)>; +def : Pat<(truncstorei8 GR64:$src, addr_MO10:$dst), (STB addr_MO10:$dst, GR64:$src)>; + +def : Pat<(store GR64:$src, GR64:$dst), (STW GR64:$dst, (i16 0), GR64:$src)>; +def : Pat<(store GR64:$src, addr_MO10:$dst), (STW addr_MO10:$dst, GR64:$src)>; + + +//===----------------------------------------------------------------------===// +// Branch Operations +//===----------------------------------------------------------------------===// + +multiclass BRCC cc, string opname> { + // Branches may expand to short equivalents in peephole + def _ : Inst_i10_rr + <0x2, cc, (outs), (ins brtarget:$imm, GR64:$rA, GR64:$rB), + !strconcat(opname, "\t$imm, $rA, $rB"), []>; + // Don't assemble short branch instructions + let isCodeGenOnly = 1 in { + def _short : Inst_i3_rr_short + <0x2, cc, (outs), (ins brtarget:$imm, GR8:$rA, GR8:$rB), + !strconcat(opname, "\t$imm, $rA, $rB"), []>; + } +} + +let isBranch = 1, isTerminator = 1, isBarrier = 1 in { + defm BEQ : BRCC<0x2, "beq">; + defm BNE : BRCC<0x3, "bne">; + defm BLTS : BRCC<0x4, "blts">; + defm BLES : BRCC<0x5, "bles">; + defm BLTU : BRCC<0x6, "bltu">; + defm BLEU : BRCC<0x7, "bleu">; + + // BRA may expand to short equivalent in the peephole + def BRA : Inst_i22 + <0x2, 0x0, (outs), (ins brtarget:$imm), "bra\t$imm", [(br bb:$imm)]>; + // Don't assemble short branch instructions + let isCodeGenOnly = 1 in { + def BRA_short : Inst_i9_short + <0x2, 0x0, (outs), (ins brtarget:$imm), "bra\t$imm", []>; + } +} + +// Implements the BR_CC DAG node. Expanded into one of the above branches. +let isBranch = 1, isTerminator = 1, isBarrier = 1, usesCustomInserter = 1 in { + def BR_CC : Pseudo + <(outs), (ins i16imm:$cc, GR64:$lhs, GR64:$rhs, brtarget:$target), + "#BR_CC", [(AAPbrcc imm:$cc, GR64:$lhs, GR64:$rhs, bb:$target)]>; +} + +// Implements the SELECT_CC DAG node. Expanded into a branch sequence +let usesCustomInserter = 1 in { + def SELECT_CC : Pseudo + <(outs GR64:$dst), + (ins GR64:$lhs, GR64:$rhs, GR64:$T, GR64:$F, i16imm:$cc), + "#SELECT_CC", + [(set GR64:$dst, + (AAPselectcc GR64:$lhs, GR64:$rhs, GR64:$T, GR64:$F, imm:$cc))]>; +} + + +//===----------------------------------------------------------------------===// +// Calls and returns +//===----------------------------------------------------------------------===// + +// Mark R0 as a def as it is the link register +let isCall = 1, Uses = [R1], Defs = [R0] in { + +// Never assemble short branches +let isCodeGenOnly = 1 in { + def BAL_short : Inst_i6_r_short + <0x2, 0x1, (outs), (ins i16imm:$imm, GR8:$rB), "bal\t$imm, $rB", []>; +} + +// BAL may expand to BAL_short in peephole +def BAL : Inst_i16_r + <0x2, 0x1, (outs), (ins i16imm:$imm, GR64:$rB), "bal\t$imm, $rB", []>; + +def JAL_short : Inst_rrr_short + <0x2, 0x9, (outs), (ins GR8:$rD, GR64:$rB), "jal\t$rD, $rB", []> { + let rA = 0; + } + +// JAL may expand to JAL_short in peephole +def JAL : Inst_rrr + <0x2, 0x9, (outs), (ins GR64:$rD, GR64:$rB), "jal\t$rD, $rB", []> { + let rA = 0; + } +} // End of isCall, Uses, Defs + +// Calls are encoded as a branch through the link register +/*def : Pat<(callflag (i16 imm:$imm), GR64:$rB), (BAL imm:$imm, GR64:$rB)>;*/ + + +let isReturn = 1, isTerminator = 1, isBarrier = 1 in { +// May expand to JMP_short in peephole +def JMP : Inst_r<0x2, 0x8, (outs), (ins GR64:$rD), "jmp\t$rD", []>; +def JMP_short : Inst_r_short<0x2, 0x8, (outs), (ins GR8:$rD), "jmp\t$rD", []>; +} // end of isReturn, isTerminator, isBarrier + +// Indirect calls are a jump through a register +def : Pat<(callflag GR64:$rD, GR64:$rB), (JAL GR64:$rD, GR64:$rB)>; + +// Returns are encoded as a jump through the link register +def : Pat<(retflag GR64:$rD), (JMP GR64:$rD)>; + + +// Stack adjustment +let Defs = [R1], Uses = [R1] in { +def ADJCALLSTACKDOWN : Pseudo + <(outs), (ins i16imm:$amt), "#ADJCALLSTACKDOWN", + [(callseq_start timm:$amt)]>; + +def ADJCALLSTACKUP : Pseudo + <(outs), (ins i16imm:$amt1, i16imm:$amt2), "#ADJCALLSTACKUP", + [(callseq_end timm:$amt1, timm:$amt2)]>; +} + +// Call patterns +def : Pat<(callflag (i16 tglobaladdr:$dst), GR64:$rA), (BAL tglobaladdr:$dst, GR64:$rA)>; +def : Pat<(callflag (i16 texternalsym:$dst), GR64:$rA), (BAL texternalsym:$dst, GR64:$rA)>; + + +//===----------------------------------------------------------------------===// +// Peephole Patterns +//===----------------------------------------------------------------------===// +def : Pat<(addc GR64:$src1, GR64:$src2), (ADD_r GR64:$src1, GR64:$src2)>; + +def : Pat<(i16 (aapwrapper tglobaladdr:$dst)), (MOVI_i16 tglobaladdr:$dst)>; +def : Pat<(i16 (aapwrapper texternalsym:$dst)), (MOVI_i16 texternalsym:$dst)>; +def : Pat<(i16 (aapwrapper tblockaddress:$dst)), (MOVI_i16 tblockaddress:$dst)>; 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 "AAP.h" +#include "AAPSubtarget.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/AAPRegisterInfo.td =================================================================== --- /dev/null +++ lib/Target/AAP/AAPRegisterInfo.td @@ -0,0 +1,35 @@ +//===- AAPRegisterInfo.td - AAP Register defs ------------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Declarations that describe the AAP register file +//===----------------------------------------------------------------------===// + +class AAPReg : Register { + field bits<6> Num; + let Namespace = "AAP"; +} + +// Registers are identified with 5-bit ID numbers. +// Ri - 16-bit integer registers +class Ri num, string n> : AAPReg { + let Num = num; + let HWEncoding{5-0} = num; +} + +foreach I = 0-63 in +def R#I : Ri, DwarfRegNum<[I]>; + +// PSW holds the carry flag +def PSW : AAPReg<"psw">, DwarfRegNum<[64]>; + + +// Register classes. +def GR8 : RegisterClass<"AAP", [i16], 16, (add (sequence "R%u", 0, 7))>; +def GR64 : RegisterClass<"AAP", [i16], 16, (add (sequence "R%u", 0, 63))>; 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/AAPShortInstrPeephole.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AAPShortInstrPeephole.cpp @@ -0,0 +1,366 @@ +//===------- AAPShortInstrPeephole.cpp - Pick shorter instructions --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Simple pass to replace long instructions with shorter equivalents +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "short-instr-peephole" + +#include "AAP.h" +#include "AAPRegisterInfo.h" +#include "AAPTargetMachine.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/Support/Debug.h" + +using namespace llvm; + +namespace { +struct ShortInstrPeephole : public MachineFunctionPass { + /// Target machine description used to query for register names, data + /// layout and similar. + TargetMachine &TM; + const MCInstrInfo &MII; + + static char ID; + ShortInstrPeephole(TargetMachine &TM) + : MachineFunctionPass(ID), TM(TM), MII(*TM.getMCInstrInfo()) {} + + const char *getPassName() const override { + return "AAP Short Instruction Peephole"; + } + + bool runOnMachineFunction(MachineFunction &MF) override; + bool runOnInstruction(MachineInstr &MI) const; + + bool updateMOV_r(MachineInstr &MI) const; + bool updateMOVI_i16(MachineInstr &MI) const; + bool updateNOP(MachineInstr &MI) const; + bool updateALU_r(MachineInstr &MI) const; + bool updateARITH_i10(MachineInstr &MI) const; + bool updateSHIFT_i6(MachineInstr &MI) const; + bool updateLD(MachineInstr &MI) const; + bool updateST(MachineInstr &MI) const; + bool updateBRA(MachineInstr &MI) const; + bool updateBAL(MachineInstr &MI) const; + bool updateJMP(MachineInstr &MI) const; + bool updateJAL(MachineInstr &MI) const; +}; + +char ShortInstrPeephole::ID = 0; +} // end of anonymous namespace + +FunctionPass *llvm::createAAPShortInstrPeepholePass(AAPTargetMachine &TM) { + return new ShortInstrPeephole(TM); +} + +bool ShortInstrPeephole::runOnMachineFunction(MachineFunction &MF) { + bool Changed = false; + for (MachineBasicBlock &MBB : MF) { + for (MachineInstr &MI : MBB) { + Changed |= runOnInstruction(MI); + } + } + return Changed; +} + +bool ShortInstrPeephole::runOnInstruction(MachineInstr &MI) const { + switch (MI.getOpcode()) { + case AAP::MOV_r: + return updateMOV_r(MI); + case AAP::MOVI_i16: + return updateMOVI_i16(MI); + case AAP::NOP: + return updateNOP(MI); + + case AAP::ADD_r: + case AAP::AND_r: + case AAP::OR_r: + case AAP::XOR_r: + case AAP::SUB_r: + case AAP::ASR_r: + case AAP::LSL_r: + case AAP::LSR_r: + return updateALU_r(MI); + + case AAP::ADDI_i10: + case AAP::SUBI_i10: + return updateARITH_i10(MI); + + case AAP::ASRI_i6: + case AAP::LSLI_i6: + case AAP::LSRI_i6: + return updateSHIFT_i6(MI); + + case AAP::LDB: + case AAP::LDW: + case AAP::LDB_postinc: + case AAP::LDW_postinc: + case AAP::LDB_predec: + case AAP::LDW_predec: + return updateLD(MI); + + case AAP::STB: + case AAP::STW: + case AAP::STB_postinc: + case AAP::STW_postinc: + case AAP::STB_predec: + case AAP::STW_predec: + return updateST(MI); + + case AAP::BRA: + return updateBRA(MI); + case AAP::BAL: + return updateBAL(MI); + case AAP::JAL: + return updateJAL(MI); + case AAP::JMP: + return updateJMP(MI); + + default: + return false; + } +} + +bool ShortInstrPeephole::updateMOV_r(MachineInstr &MI) const { + const auto &DstReg = MI.getOperand(0).getReg(); + const auto &SrcReg = MI.getOperand(1).getReg(); + + if (AAP::GR8RegClass.contains(DstReg, SrcReg)) { + MI.setDesc(MII.get(AAP::MOV_r_short)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateMOVI_i16(MachineInstr &MI) const { + unsigned DstReg = MI.getOperand(0).getReg(); + const auto &Imm = MI.getOperand(1); + + if (AAP::GR8RegClass.contains(DstReg) && Imm.isImm() && + AAP::isImm6(Imm.getImm())) { + MI.setDesc(MII.get(AAP::MOVI_i6_short)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateNOP(MachineInstr &MI) const { + unsigned SrcReg = MI.getOperand(0).getReg(); + const auto &Imm = MI.getOperand(1); + + if (AAP::GR8RegClass.contains(SrcReg) && Imm.isImm() && + AAP::isImm6(Imm.getImm())) { + MI.setDesc(MII.get(AAP::NOP_short)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateALU_r(MachineInstr &MI) const { + unsigned DstReg = MI.getOperand(0).getReg(); + unsigned Op1Reg = MI.getOperand(1).getReg(); + unsigned Op2Reg = MI.getOperand(2).getReg(); + + if (AAP::GR8RegClass.contains(DstReg) && AAP::GR8RegClass.contains(Op1Reg) && + AAP::GR8RegClass.contains(Op2Reg)) { + unsigned Opcode = MI.getOpcode(); + switch (Opcode) { + case AAP::ADD_r: + Opcode = AAP::ADD_r_short; + break; + case AAP::AND_r: + Opcode = AAP::AND_r_short; + break; + case AAP::OR_r: + Opcode = AAP::OR_r_short; + break; + case AAP::XOR_r: + Opcode = AAP::XOR_r_short; + break; + case AAP::SUB_r: + Opcode = AAP::SUB_r_short; + break; + case AAP::ASR_r: + Opcode = AAP::ASR_r_short; + break; + case AAP::LSL_r: + Opcode = AAP::LSL_r_short; + break; + case AAP::LSR_r: + Opcode = AAP::LSR_r_short; + break; + default: + llvm_unreachable("Unknown opcode"); + } + MI.setDesc(MII.get(Opcode)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateARITH_i10(MachineInstr &MI) const { + unsigned DstReg = MI.getOperand(0).getReg(); + unsigned SrcReg = MI.getOperand(1).getReg(); + const auto &Imm = MI.getOperand(2); + + if (AAP::GR8RegClass.contains(DstReg, SrcReg) && Imm.isImm() && + AAP::isImm3(Imm.getImm())) { + unsigned Opcode = MI.getOpcode(); + switch (Opcode) { + case AAP::ADDI_i10: + Opcode = AAP::ADDI_i3_short; + break; + case AAP::SUBI_i10: + Opcode = AAP::SUBI_i3_short; + break; + } + MI.setDesc(MII.get(Opcode)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateSHIFT_i6(MachineInstr &MI) const { + unsigned DstReg = MI.getOperand(0).getReg(); + unsigned SrcReg = MI.getOperand(1).getReg(); + const auto &Imm = MI.getOperand(2); + + if (AAP::GR8RegClass.contains(DstReg, SrcReg) && Imm.isImm() && + AAP::isShiftImm3(Imm.getImm())) { + unsigned Opcode = MI.getOpcode(); + switch (Opcode) { + case AAP::ASRI_i6: + Opcode = AAP::ASRI_i3_short; + break; + case AAP::LSLI_i6: + Opcode = AAP::LSLI_i3_short; + break; + case AAP::LSRI_i6: + Opcode = AAP::LSRI_i3_short; + break; + } + MI.setDesc(MII.get(Opcode)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateLD(MachineInstr &MI) const { + unsigned DstReg = MI.getOperand(0).getReg(); + const auto &Base = MI.getOperand(1); + const auto &Off = MI.getOperand(2); + + if (AAP::GR8RegClass.contains(DstReg) && Base.isReg() && + AAP::GR8RegClass.contains(Base.getReg()) && Off.isImm() && + AAP::isOff3(Off.getImm())) { + unsigned Opcode = MI.getOpcode(); + switch (Opcode) { + case AAP::LDB: + Opcode = AAP::LDB_short; + break; + case AAP::LDW: + Opcode = AAP::LDW_short; + break; + case AAP::LDB_postinc: + Opcode = AAP::LDB_postinc_short; + break; + case AAP::LDW_postinc: + Opcode = AAP::LDW_postinc_short; + break; + case AAP::LDB_predec: + Opcode = AAP::LDB_predec_short; + break; + case AAP::LDW_predec: + Opcode = AAP::LDW_predec_short; + break; + } + MI.setDesc(MII.get(Opcode)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateST(MachineInstr &MI) const { + const auto &Base = MI.getOperand(0); + const auto &Off = MI.getOperand(1); + unsigned SrcReg = MI.getOperand(2).getReg(); + + if (Base.isReg() && AAP::GR8RegClass.contains(Base.getReg()) && Off.isImm() && + AAP::isOff3(Off.getImm()) && AAP::GR8RegClass.contains(SrcReg)) { + unsigned Opcode = MI.getOpcode(); + switch (Opcode) { + case AAP::STB: + Opcode = AAP::STB_short; + break; + case AAP::STW: + Opcode = AAP::STW_short; + break; + case AAP::STB_postinc: + Opcode = AAP::STB_postinc_short; + break; + case AAP::STW_postinc: + Opcode = AAP::STW_postinc_short; + break; + case AAP::STB_predec: + Opcode = AAP::STB_predec_short; + break; + case AAP::STW_predec: + Opcode = AAP::STW_predec_short; + break; + } + MI.setDesc(MII.get(Opcode)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateBRA(MachineInstr &MI) const { + const auto &MO = MI.getOperand(0); + if (MO.isImm() && AAP::isOff9(MO.getImm())) { + MI.setDesc(MII.get(AAP::BRA_short)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateBAL(MachineInstr &MI) const { + const auto &MO = MI.getOperand(0); + unsigned LinkReg = MI.getOperand(1).getReg(); + + if (MO.isImm() && AAP::isOff6(MO.getImm()) && + AAP::GR8RegClass.contains(LinkReg)) { + MI.setDesc(MII.get(AAP::BAL_short)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateJMP(MachineInstr &MI) const { + unsigned LinkReg = MI.getOperand(0).getReg(); + if (AAP::GR8RegClass.contains(LinkReg)) { + MI.setDesc(MII.get(AAP::JMP_short)); + return true; + } + return false; +} + +bool ShortInstrPeephole::updateJAL(MachineInstr &MI) const { + unsigned TargetReg = MI.getOperand(0).getReg(); + unsigned LinkReg = MI.getOperand(1).getReg(); + + if (AAP::GR8RegClass.contains(TargetReg, LinkReg)) { + MI.setDesc(MII.get(AAP::JAL_short)); + return true; + } + return false; +} 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,47 @@ +//===-- 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, Reloc::Model 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 =================================================================== --- /dev/null +++ lib/Target/AAP/AAPTargetMachine.cpp @@ -0,0 +1,68 @@ +//===-- AAPTargetMachine.cpp - Define TargetMachine for AAP ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements the info about AAP target spec. +// +//===----------------------------------------------------------------------===// + +#include "AAP.h" +#include "AAPTargetMachine.h" +#include "llvm/ADT/Triple.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +extern "C" void LLVMInitializeAAPTarget() { + // Register the target + RegisterTargetMachine X(TheAAPTarget); +} + +AAPTargetMachine::AAPTargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Reloc::Model 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, 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; + void addPreEmitPass() override; +}; +} // namespace + +TargetPassConfig *AAPTargetMachine::createPassConfig(PassManagerBase &PM) { + return new AAPPassConfig(this, PM); +} + +bool AAPPassConfig::addInstSelector() { + addPass(createAAPISelDag(getAAPTargetMachine(), getOptLevel())); + return false; +} + +void AAPPassConfig::addPreEmitPass() { + addPass(createAAPShortInstrPeepholePass(getAAPTargetMachine()), false); +} Index: lib/Target/AAP/AsmParser/AAPAsmParser.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/AsmParser/AAPAsmParser.cpp @@ -0,0 +1,677 @@ +//===-- AAPAsmParser.cpp - Parse AAP assembly to MCInst instructions ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AAP.h" +#include "MCTargetDesc/AAPMCTargetDesc.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +namespace { +struct AAPOperand; + +class AAPAsmParser : public MCTargetAsmParser { + MCAsmParser &Parser; + const MCRegisterInfo *MRI; + + MCAsmParser &getParser() const { return Parser; } + MCAsmLexer &getLexer() const { return Parser.getLexer(); } + + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, + bool matchingInlineAsm) override; + + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + + std::unique_ptr ParseRegister(unsigned &RegNo); + std::unique_ptr ParseImmediate(); + std::unique_ptr ParseMemSrc(); + + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + + bool ParseDirective(AsmToken DirectiveID) override; + + bool ParseOperand(OperandVector &Operands); + +// Auto-generated instruction matching functions +#define GET_ASSEMBLER_HEADER +#include "AAPGenAsmMatcher.inc" + +public: + AAPAsmParser(const MCSubtargetInfo &sti, MCAsmParser &_Parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(Options, sti), Parser(_Parser) { + setAvailableFeatures(ComputeAvailableFeatures(sti.getFeatureBits())); + + // Cache the machine register info for later + MRI = Parser.getContext().getRegisterInfo(); + } + + unsigned checkTargetMatchPredicate(MCInst &Inst) override { + // Check instructions with memsrc operands here, as they cannot be + // checked through the instruction match classes. + + // If this is a short load/store instruction, then we must check that + // its register operands are all in the GR8 reg class. + const MCRegisterClass &MRC = MRI->getRegClass(AAP::GR8RegClassID); + + switch (Inst.getOpcode()) { + default: + return Match_Success; + case AAP::LDB_short: + case AAP::LDW_short: + case AAP::LDB_postinc_short: + case AAP::LDW_postinc_short: + case AAP::LDB_predec_short: + case AAP::LDW_predec_short: + case AAP::STB_short: + case AAP::STW_short: + case AAP::STB_postinc_short: + case AAP::STW_postinc_short: + case AAP::STB_predec_short: + case AAP::STW_predec_short: + break; + } + + for (MCInst::iterator I = Inst.begin(); I != Inst.end(); ++I) { + if (I->isReg() && !MRC.contains(I->getReg())) { + return Match_InvalidOperand; + } + } + return Match_Success; + } +}; + +/// AAPOperand - Instances of this class represented a parsed machine +/// instruction +struct AAPOperand : public MCParsedAsmOperand { + + enum KindTy { Token, Register, Immediate, MemSrc } Kind; + + struct TokOp { + const char *Data; + unsigned Length; + }; + + struct RegOp { + unsigned RegNum; + }; + + struct ImmOp { + const MCExpr *Val; + }; + + struct MemOp { + bool WithPreDec; + unsigned RegNum; + bool WithPostInc; + const MCExpr *Offset; + }; + + SMLoc StartLoc, EndLoc; + union { + TokOp Tok; + RegOp Reg; + ImmOp Imm; + MemOp Mem; + }; + + AAPOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} + +public: + AAPOperand(const AAPOperand &o) : MCParsedAsmOperand() { + Kind = o.Kind; + StartLoc = o.StartLoc; + EndLoc = o.EndLoc; + switch (Kind) { + case Register: + Reg = o.Reg; + break; + case Immediate: + Imm = o.Imm; + break; + case Token: + Tok = o.Tok; + break; + case MemSrc: + Mem = o.Mem; + } + } + + /// getStartLoc - Gets location of the first token of this operand + SMLoc getStartLoc() const { return StartLoc; } + + /// getEndLoc - Gets location of the last token of this operand + SMLoc getEndLoc() const { return EndLoc; } + + unsigned getReg() const { + assert(Kind == Register && "Invalid type access!"); + return Reg.RegNum; + } + + const MCExpr *getImm() const { + assert(Kind == Immediate && "Invalid type access!"); + return Imm.Val; + } + + StringRef getToken() const { + assert(Kind == Token && "Invalid type access!"); + return StringRef(Tok.Data, Tok.Length); + } + + unsigned getMemSrcReg() const { + assert(Kind == MemSrc && "Invalid type access!"); + return Mem.RegNum; + } + + const MCExpr *getMemSrcImm() const { + assert(Kind == MemSrc && "Invalid type access!"); + return Mem.Offset; + } + + static bool isConst(const MCExpr *Imm) { + return Imm->getKind() == MCExpr::Constant; + } + + static bool isConst3(const MCExpr *I) { + if (!isConst(I)) + return false; + int64_t Res; + I->evaluateAsAbsolute(Res); + return AAP::isImm3(Res); + } + static bool isConst6(const MCExpr *I) { + if (!isConst(I)) + return false; + int64_t Res; + I->evaluateAsAbsolute(Res); + return AAP::isImm6(Res); + } + + static bool isImm6(const MCExpr *I) { + int64_t Res; + if (I->evaluateAsAbsolute(Res)) + return AAP::isImm6(Res); + return true; + } + static bool isImm9(const MCExpr *I) { + int64_t Res; + if (I->evaluateAsAbsolute(Res)) + return AAP::isImm9(Res); + return true; + } + static bool isImm10(const MCExpr *I) { + int64_t Res; + if (I->evaluateAsAbsolute(Res)) + return AAP::isImm10(Res); + return true; + } + static bool isImm12(const MCExpr *I) { + int64_t Res; + if (I->evaluateAsAbsolute(Res)) + return AAP::isImm12(Res); + return true; + } + + static bool isField16(const MCExpr *I) { + int64_t Res; + if (I->evaluateAsAbsolute(Res)) + return AAP::isField16(Res); + return true; + } + + static bool isOff3(const MCExpr *I) { + if (!isConst(I)) + return false; + int64_t Res; + I->evaluateAsAbsolute(Res); + return AAP::isOff3(Res); + } + static bool isOff10(const MCExpr *I) { + int64_t Res; + if (I->evaluateAsAbsolute(Res)) + return AAP::isOff10(Res); + return true; + } + + static bool isShiftConst3(const MCExpr *I) { + if (!isConst(I)) + return false; + int64_t Res; + I->evaluateAsAbsolute(Res); + return AAP::isShiftImm3(Res); + } + static bool isShiftImm6(const MCExpr *I) { + int64_t Res; + if (I->evaluateAsAbsolute(Res)) + return AAP::isShiftImm6(Res); + return true; + } + + // Functions for testing operand type + bool isReg() const { return Kind == Register; } + bool isImm() const { return Kind == Immediate; } + + bool isConst3() const { return isImm() && isConst3(getImm()); } + bool isConst6() const { return isImm() && isConst6(getImm()); } + + bool isImm6() const { return isImm() && isImm6(getImm()); } + bool isImm9() const { return isImm() && isImm9(getImm()); } + bool isImm10() const { return isImm() && isImm10(getImm()); } + bool isImm12() const { return isImm() && isImm12(getImm()); } + + bool isField16() const { return isImm() && isField16(getImm()); } + + bool isOff3() const { return isImm() && isOff3(getImm()); } + bool isOff10() const { return isImm() && isOff10(getImm()); } + + bool isShiftConst3() const { return isImm() && isShiftConst3(getImm()); } + bool isShiftImm6() const { return isImm() && isShiftImm6(getImm()); } + + bool isToken() const { return Kind == Token; } + bool isMem() const { return false; } + + // Check that the immediate fits in an imm6 + bool isMemSrc10() const { + if (Kind != MemSrc || Mem.WithPreDec || Mem.WithPostInc) { + return false; + } + // AAPAsmParser::checkTargetMatchPredicate checks that the register is + // is in the GR64 class + return isOff10(getMemSrcImm()); + } + bool isMemSrc10PostInc() const { + if (Kind != MemSrc) { + return false; + } + if (Mem.WithPreDec) { + return false; + } + if (!Mem.WithPostInc) { + return false; + } + // AAPAsmParser::checkTargetMatchPredicate checks that the register is + // is in the GR64 class + return isOff10(getMemSrcImm()); + } + bool isMemSrc10PreDec() const { + if (Kind != MemSrc) { + return false; + } + if (!Mem.WithPreDec) { + return false; + } + if (Mem.WithPostInc) { + return false; + } + // AAPAsmParser::checkTargetMatchPredicate checks that the register is + // is in the GR64 class + return isOff10(getMemSrcImm()); + } + + // Check that the immediate fits in an const3. A memsrc3 operand may only + // have a constant in its immediate field. + bool isMemSrc3() const { + if (Kind != MemSrc || Mem.WithPreDec || Mem.WithPostInc) { + return false; + } + // AAPAsmParser::checkTargetMatchPredicate checks that the register is + // is in the GR8 class + return isOff3(getMemSrcImm()); + } + bool isMemSrc3PostInc() const { + if (Kind != MemSrc) { + return false; + } + if (Mem.WithPreDec) { + return false; + } + if (!Mem.WithPostInc) { + return false; + } + // AAPAsmParser::checkTargetMatchPredicate checks that the register is + // is in the GR8 class + return isOff3(getMemSrcImm()); + } + bool isMemSrc3PreDec() const { + if (Kind != MemSrc) { + return false; + } + if (!Mem.WithPreDec) { + return false; + } + if (Mem.WithPostInc) { + return false; + } + // AAPAsmParser::checkTargetMatchPredicate checks that the register is + // is in the GR8 class + return isOff3(getMemSrcImm()); + } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + // Add as immediates where possible. Null MCExpr = 0 + if (Expr == 0) + Inst.addOperand(MCOperand::createImm(0)); + else if (const MCConstantExpr *CE = dyn_cast(Expr)) + Inst.addOperand(MCOperand::createImm(CE->getValue())); + else + Inst.addOperand(MCOperand::createExpr(Expr)); + } + + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getReg())); + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + + void addMemSrcOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getMemSrcReg())); + addExpr(Inst, getMemSrcImm()); + } + void addMemSrc10Operands(MCInst &Inst, unsigned N) const { + addMemSrcOperands(Inst, N); + } + void addMemSrc10PostIncOperands(MCInst &Inst, unsigned N) const { + addMemSrcOperands(Inst, N); + } + void addMemSrc10PreDecOperands(MCInst &Inst, unsigned N) const { + addMemSrcOperands(Inst, N); + } + void addMemSrc3Operands(MCInst &Inst, unsigned N) const { + addMemSrcOperands(Inst, N); + } + void addMemSrc3PostIncOperands(MCInst &Inst, unsigned N) const { + addMemSrcOperands(Inst, N); + } + void addMemSrc3PreDecOperands(MCInst &Inst, unsigned N) const { + addMemSrcOperands(Inst, N); + } + + // FIXME: Implement this + void print(raw_ostream &OS) const {} + + static std::unique_ptr CreateToken(StringRef Str, SMLoc S) { + auto Op = make_unique(Token); + Op->Tok.Data = Str.data(); + Op->Tok.Length = Str.size(); + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static std::unique_ptr CreateReg(unsigned RegNo, SMLoc S, + SMLoc E) { + auto Op = make_unique(Register); + Op->Reg.RegNum = RegNo; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr CreateImm(const MCExpr *Val, SMLoc S, + SMLoc E) { + auto Op = make_unique(Immediate); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr + CreateMemSrc(unsigned RegNo, const MCExpr *Offset, bool WithPreDec, + bool WithPostInc, SMLoc S, SMLoc E) { + auto Op = make_unique(MemSrc); + Op->Mem.WithPreDec = WithPreDec; + Op->Mem.RegNum = RegNo; + Op->Mem.WithPostInc = WithPostInc; + Op->Mem.Offset = Offset; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } +}; +} // end anonymous namespace. + +// Auto-generated by TableGen +static unsigned MatchRegisterName(StringRef Name); +static const char *getSubtargetFeatureName(uint64_t Val); + +bool AAPAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, uint64_t &ErrorInfo, + bool matchingInlineAsm) { + MCInst Inst; + SMLoc ErrorLoc; + + switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, matchingInlineAsm)) { + default: + break; + case Match_Success: + Out.EmitInstruction(Inst, getSTI()); + return false; + case Match_MissingFeature: { + assert(ErrorInfo && "Unknown missing feature!"); + std::string Msg = "Use of this instruction requires:"; + unsigned Mask = 1; + for (unsigned i = 0; i < (sizeof(ErrorInfo) * 8 - 1); ++i) { + if (ErrorInfo & Mask) { + Msg += " "; + Msg += getSubtargetFeatureName(ErrorInfo & Mask); + } + Mask <<= 1; + } + return Error(IDLoc, Msg); + } + case Match_MnemonicFail: + return Error(IDLoc, "Unrecognized instruction mnemonic"); + case Match_InvalidOperand: + ErrorLoc = IDLoc; + if (ErrorInfo != ~0U) { + if (ErrorInfo >= Operands.size()) + return Error(IDLoc, "Too few operands for instruction"); + + ErrorLoc = ((AAPOperand &)*Operands[ErrorInfo]).getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + return Error(IDLoc, "Invalid operand for instruction"); + } + + llvm_unreachable("Unknown match type detected!"); +} + +bool AAPAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) { + return (ParseRegister(RegNo) == nullptr); +} + +std::unique_ptr AAPAsmParser::ParseRegister(unsigned &RegNo) { + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + // Registers have '$' prefix + if (getLexer().getKind() != AsmToken::Dollar) { + return nullptr; + } + getLexer().Lex(); + + switch (getLexer().getKind()) { + default: + return nullptr; + case AsmToken::Identifier: + std::string lowerCaseStr = getLexer().getTok().getString().lower(); + + RegNo = MatchRegisterName(lowerCaseStr); + if (RegNo == 0) { + return nullptr; + } + getLexer().Lex(); + return AAPOperand::CreateReg(RegNo, S, E); + } +} + +std::unique_ptr AAPAsmParser::ParseImmediate() { + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + const MCExpr *EVal; + if (!getParser().parseExpression(EVal, E)) { + return AAPOperand::CreateImm(EVal, S, E); + } + return nullptr; +} + +std::unique_ptr AAPAsmParser::ParseMemSrc() { + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + bool WithPreDec = false; + bool WithPostInc = false; + + // First check for a '-', signifying a predecrement + if (getLexer().getKind() == AsmToken::Minus) { + getLexer().Lex(); + WithPreDec = true; + } + + unsigned RegNo; + std::unique_ptr RegOp = ParseRegister(RegNo); + if (!RegOp) { + Error(Parser.getTok().getLoc(), "Missing register in memsrc operand"); + return nullptr; + } + RegNo = RegOp->getReg(); + + // Check for a '+' signifying a post increment + if (getLexer().getKind() == AsmToken::Plus) { + getLexer().Lex(); + WithPostInc = true; + } + + if (!getLexer().is(AsmToken::Comma)) { + Error(Parser.getTok().getLoc(), "Missing ',' separator in memsrc operand"); + return nullptr; + } + Parser.Lex(); + + std::unique_ptr ImmOp = ParseImmediate(); + if (!ImmOp) { + Error(Parser.getTok().getLoc(), "Missing immediate in memsrc operand"); + return nullptr; + } + const MCExpr *ImmVal = ImmOp->getImm(); + + return AAPOperand::CreateMemSrc(RegNo, ImmVal, WithPreDec, WithPostInc, S, E); +} + +/// Looks at a token type and creates the relevant operand +/// from this information, adding to Operands. +/// If operand was parsed, returns false, else true. +bool AAPAsmParser::ParseOperand(OperandVector &Operands) { + std::unique_ptr Op = nullptr; + + // Attempt to parse token as register + unsigned RegNo; + Op = ParseRegister(RegNo); + if (Op) { + Operands.push_back(std::move(Op)); + return false; + } + + // If we see a '[', that implies a memsrc follows + if (getLexer().getKind() == AsmToken::LBrac) { + SMLoc S = Parser.getTok().getLoc(); + Operands.push_back(AAPOperand::CreateToken("[", S)); + Parser.Lex(); // Eat '[' + + Op = ParseMemSrc(); + + if (Op) { + Operands.push_back(std::move(Op)); + + S = Parser.getTok().getLoc(); + if (getLexer().getKind() == AsmToken::RBrac) { + Operands.push_back(AAPOperand::CreateToken("]", S)); + Parser.Lex(); // Eat ']' + } else { + Error(S, "Missing closing brace for memsrc operand"); + return true; + } + return false; + } + } + + // Attempt to parse token as an immediate + Op = ParseImmediate(); + if (Op) { + Operands.push_back(std::move(Op)); + return false; + } + + // Finally we have exhausted all options and must declare defeat. + Error(Parser.getTok().getLoc(), "Unknown operand"); + return true; +} + +bool AAPAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { + // First operand is token for instruction + Operands.push_back(AAPOperand::CreateToken(Name, NameLoc)); + + // If there are no more operands, then finish + if (getLexer().is(AsmToken::EndOfStatement)) + return false; + + // Parse first operand + if (ParseOperand(Operands)) + return true; + + // Parse until end of statement, consuming commas between operands + while (getLexer().isNot(AsmToken::EndOfStatement) && + getLexer().is(AsmToken::Comma)) { + // Consume comma token + getLexer().Lex(); + + // Parse next operand + if (ParseOperand(Operands)) + return true; + } + + // consume end of statement + return false; +} + +bool AAPAsmParser::ParseDirective(AsmToken DirectiveID) { return true; } + +extern "C" void LLVMInitializeAAPAsmParser() { + RegisterMCAsmParser X(TheAAPTarget); +} + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#define GET_SUBTARGET_FEATURE_NAME +#include "AAPGenAsmMatcher.inc" Index: lib/Target/AAP/AsmParser/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/AAP/AsmParser/CMakeLists.txt @@ -0,0 +1,5 @@ +add_llvm_library(LLVMAAPAsmParser + AAPAsmParser.cpp + ) + +add_dependencies(LLVMAAPAsmParser AAPCommonTableGen) Index: lib/Target/AAP/AsmParser/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/AAP/AsmParser/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/AAP/AsmParser/LLVMBuild.txt ----------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = AAPAsmParser +parent = AAP +required_libraries = MC MCParser Support AAPDesc AAPInfo +add_to_library_groups = AAP Index: lib/Target/AAP/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/AAP/CMakeLists.txt @@ -0,0 +1,33 @@ +set(LLVM_TARGET_DEFINITIONS AAP.td) + +tablegen(LLVM AAPGenRegisterInfo.inc -gen-register-info) +tablegen(LLVM AAPGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM AAPGenDisassemblerTables.inc -gen-disassembler) +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 + AAPShortInstrPeephole.cpp + ) + +add_subdirectory(Disassembler) +add_subdirectory(InstPrinter) +add_subdirectory(MCTargetDesc) +add_subdirectory(TargetInfo) +add_subdirectory(AsmParser) Index: lib/Target/AAP/Disassembler/AAPDisassembler.h =================================================================== --- /dev/null +++ lib/Target/AAP/Disassembler/AAPDisassembler.h @@ -0,0 +1,36 @@ +//===-- AAPDisassembler.h - AAP Disassembler ----------------------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef AAPDISASSEMBLER_H +#define AAPDISASSEMBLER_H + +#include "llvm/MC/MCDisassembler/MCDisassembler.h" + +// Pull DecodeStatus and its enum values into the global namespace. +typedef llvm::MCDisassembler::DecodeStatus DecodeStatus; + +namespace llvm { +class MCInst; +class MemoryObject; +class raw_ostream; + +class AAPDisassembler : public MCDisassembler { + +public: + AAPDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) + : MCDisassembler(STI, Ctx) {} + + DecodeStatus getInstruction(MCInst &instr, uint64_t &size, + ArrayRef Bytes, uint64_t address, + raw_ostream &vStream, + raw_ostream &cStream) const override; +}; +} // namespace llvm + +#endif Index: lib/Target/AAP/Disassembler/AAPDisassembler.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/Disassembler/AAPDisassembler.cpp @@ -0,0 +1,144 @@ +//===-- AAPDisassembler.cpp - Disassembler 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 is part of the AAP Disassembler. +// +//===----------------------------------------------------------------------===// + +#include "AAP.h" +#include "AAPDisassembler.h" +#include "AAPRegisterInfo.h" +#include "AAPSubtarget.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCFixedLenDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/TargetRegistry.h" + +#define DEBUG_TYPE "AAP-disassembler" + +using namespace llvm; + +typedef MCDisassembler::DecodeStatus DecodeStatus; + +namespace llvm { +extern Target TheAAPTarget; +} + +static MCDisassembler *createAAPDisassembler(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new AAPDisassembler(STI, Ctx); +} + +extern "C" void LLVMInitializeAAPDisassembler() { + // Register the disassembler + TargetRegistry::RegisterMCDisassembler(TheAAPTarget, createAAPDisassembler); +} + +// Forward declare because the autogenerated code will reference this. +// Definition is further down. +DecodeStatus DecodeGR8RegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, const void *Decoder); +DecodeStatus DecodeGR64RegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, const void *Decoder); + +DecodeStatus decodeMemSrcOperand(MCInst &Inst, unsigned Operand, + uint64_t Address, const void *Decoder); + +DecodeStatus decodeShiftOperand(MCInst &Inst, unsigned RegNo, + uint64_t Address, const void *Decoder); + +#include "AAPGenDisassemblerTables.inc" + +DecodeStatus AAPDisassembler::getInstruction(MCInst &MI, uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, raw_ostream &os, + raw_ostream &cs) const { + uint32_t Insn; + DecodeStatus Result; + + // First try a 16-bit instruction + Insn = (Bytes[1] << 8) | (Bytes[0] << 0); + + // Next try generic 16-bit instructions + Result = decodeInstruction(DecoderTable16, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 2; + return Result; + } + + // Finally try a 32-bit instruction + Insn = + (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0); + + // Call auto-generated decoder function + Result = decodeInstruction(DecoderTable32, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + + // In case of invalid decode, assume it was a short instruction + Size = 2; + return MCDisassembler::Fail; +} + +static const unsigned AAPRegs8[] = {AAP::R0, AAP::R1, AAP::R2, AAP::R3, + AAP::R4, AAP::R5, AAP::R6, AAP::R7}; +static const unsigned AAPRegs64[] = { + AAP::R0, AAP::R1, AAP::R2, AAP::R3, AAP::R4, AAP::R5, AAP::R6, + AAP::R7, AAP::R8, AAP::R9, AAP::R10, AAP::R11, AAP::R12, AAP::R13, + AAP::R14, AAP::R15, AAP::R16, AAP::R17, AAP::R18, AAP::R19, AAP::R20, + AAP::R21, AAP::R22, AAP::R23, AAP::R24, AAP::R25, AAP::R26, AAP::R27, + AAP::R28, AAP::R29, AAP::R30, AAP::R31, AAP::R32, AAP::R33, AAP::R34, + AAP::R35, AAP::R36, AAP::R37, AAP::R38, AAP::R39, AAP::R40, AAP::R41, + AAP::R42, AAP::R43, AAP::R44, AAP::R45, AAP::R46, AAP::R47, AAP::R48, + AAP::R49, AAP::R50, AAP::R51, AAP::R52, AAP::R53, AAP::R54, AAP::R55, + AAP::R56, AAP::R57, AAP::R58, AAP::R59, AAP::R60, AAP::R61, AAP::R62, + AAP::R63}; + +template +static DecodeStatus decodeRegisterClass(MCInst &Inst, uint64_t RegNo, + const unsigned(&Regs)[N]) { + if (RegNo >= N) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::createReg(Regs[RegNo])); + return MCDisassembler::Success; +} + +DecodeStatus DecodeGR8RegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, const void *Decoder) { + return decodeRegisterClass(Inst, RegNo, AAPRegs8); +} +DecodeStatus DecodeGR64RegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, const void *Decoder) { + return decodeRegisterClass(Inst, RegNo, AAPRegs64); +} + +DecodeStatus decodeMemSrcOperand(MCInst &Inst, unsigned Operand, + uint64_t Address, const void *Decoder) { + unsigned Reg = (Operand >> 16) & 0x3f; + unsigned Offset = Operand & 0xffff; + + if (decodeRegisterClass(Inst, Reg, AAPRegs64) == MCDisassembler::Fail) { + return MCDisassembler::Fail; + } + + Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset))); + return MCDisassembler::Success; +} + +DecodeStatus decodeShiftOperand(MCInst &Inst, unsigned Operand, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::createImm(Operand + 1)); + return MCDisassembler::Success; +} Index: lib/Target/AAP/Disassembler/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/AAP/Disassembler/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMAAPDisassembler + AAPDisassembler.cpp + ) + +add_dependencies(LLVMAAPDisassembler AAPCommonTableGen) Index: lib/Target/AAP/Disassembler/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/AAP/Disassembler/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/AAP/Disassembler/LLVMBuild.txt --------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = AAPDisassembler +parent = AAP +required_libraries = Support AAPInfo MCDisassembler AAPDesc +add_to_library_groups = AAP Index: lib/Target/AAP/InstPrinter/AAPInstPrinter.h =================================================================== --- /dev/null +++ lib/Target/AAP/InstPrinter/AAPInstPrinter.h @@ -0,0 +1,57 @@ +//= AAPInstPrinter.h - Convert AAP MCInst to assembly syntax -------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints a AAP MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_AAP_INSTPRINTER_AAPINSTPRINTER_H +#define LLVM_LIB_TARGET_AAP_INSTPRINTER_AAPINSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { +class MCOperand; + +class AAPInstPrinter : public MCInstPrinter { +public: + AAPInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot, + const MCSubtargetInfo &STI) override; + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, + const char *Modifier = nullptr); + + void printPCRelImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, + const char *Modifier = nullptr); + + void printMemSrcOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, + const char *Modifier = nullptr, + bool WithPreDec = false, bool WithPostInc = false); + + void printMemSrcPostIncOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, + const char *Modifier = nullptr); + + void printMemSrcPreDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, + const char *Modifier = nullptr); + +private: + void printRegister(unsigned RegNo, raw_ostream &O) const; +}; +} + +#endif Index: lib/Target/AAP/InstPrinter/AAPInstPrinter.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/InstPrinter/AAPInstPrinter.cpp @@ -0,0 +1,103 @@ +//===-- AAPInstPrinter.cpp - Convert AAP MCInst to assembly syntax --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an AAP MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#include "AAPInstPrinter.h" +#include "AAP.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +// Include the auto-generated portion of the assembly writer. +#include "AAPGenAsmWriter.inc" + +void AAPInstPrinter::printInst(const MCInst *MI, raw_ostream &O, + StringRef Annot, const MCSubtargetInfo &STI) { + printInstruction(MI, O); + printAnnotation(O, Annot); +} + +void AAPInstPrinter::printRegister(unsigned RegNo, raw_ostream &O) const { + O << '$' << getRegisterName(RegNo); +} + +void AAPInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, const char *Modifier) { + assert((Modifier == nullptr || Modifier[0] == 0) && "No modifiers supported"); + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + printRegister(Op.getReg(), O); + } else if (Op.isImm()) { + O << Op.getImm(); + } else { + assert(Op.isExpr() && "unknown operand kind in printOperand"); + O << *Op.getExpr(); + } +} + +void AAPInstPrinter::printPCRelImmOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, + const char *Modifier) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isImm()) { + O << Op.getImm(); + } else { + assert(Op.isExpr() && "unknown pcrel immediate operand"); + O << *Op.getExpr(); + } +} + +void AAPInstPrinter::printMemSrcOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, const char *Modifier, + bool WithPreDec, bool WithPostInc) { + const MCOperand &Base = MI->getOperand(OpNo); + const MCOperand &Offset = MI->getOperand(OpNo + 1); + + if (WithPreDec) { + O << '-'; + } + + // Print register base field + if (Base.getReg()) { + printRegister(Base.getReg(), O); + } + + if (WithPostInc) { + O << '+'; + } + + O << ", "; + if (Offset.isImm()) { + O << Offset.getImm(); + } else if (Offset.isExpr()) { + O << *Offset.getExpr(); + } else { + llvm_unreachable("Expected immediate/expression in offset field"); + } +} + +void AAPInstPrinter::printMemSrcPostIncOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, + const char *Modifier) { + printMemSrcOperand(MI, OpNo, O, Modifier, false, true); +} + +void AAPInstPrinter::printMemSrcPreDecOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, + const char *Modifier) { + printMemSrcOperand(MI, OpNo, O, Modifier, true, false); +} Index: lib/Target/AAP/InstPrinter/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/AAP/InstPrinter/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMAAPAsmPrinter + AAPInstPrinter.cpp + ) Index: lib/Target/AAP/InstPrinter/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/AAP/InstPrinter/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/AAP/InstPrinter/LLVMBuild.txt ---------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = AAPAsmPrinter +parent = AAP +required_libraries = MC Support +add_to_library_groups = AAP Index: lib/Target/AAP/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/AAP/LLVMBuild.txt @@ -0,0 +1,34 @@ +;===- ./lib/Target/AAP/LLVMBuild.txt -------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[common] +subdirectories = AsmParser Disassembler InstPrinter MCTargetDesc TargetInfo + +[component_0] +type = TargetGroup +name = AAP +parent = Target +has_asmprinter = 1 +has_asmparser = 1 +has_diassembler = 1 + +[component_1] +type = Library +name = AAPCodeGen +parent = AAP +required_libraries = CodeGen Core Support Target SelectionDAG TransformUtils AAPInfo AsmPrinter AAPAsmPrinter AAPDesc MC +add_to_library_groups = AAP Index: lib/Target/AAP/MCTargetDesc/AAPAsmBackend.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/AAPAsmBackend.cpp @@ -0,0 +1,178 @@ +//===-- AAPAsmBackend.cpp - AAP Assembler Backend -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AAPMCTargetDesc.h" +#include "MCTargetDesc/AAPFixupKinds.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" + +using namespace llvm; + +namespace { + +class AAPAsmBackend : public MCAsmBackend { +public: + AAPAsmBackend(Target const &T) {} + + unsigned getNumFixupKinds() const override { return 14; } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { + const static MCFixupKindInfo Infos[AAP::NumTargetFixupKinds] = { + // We tell LLVM that branches are not PC relative to prevent it from + // resolving them, these are more complex fields which we instead want + // populate in the linker. + + // This table *must* be in the order that the fixup_* kinds are defined + // in + // AAPFixupKinds.h. + // + // Name offset size flags + {"fixup_AAP_NONE", 0, 16, 0}, + {"fixup_AAP_BR16", 0, 9, 0}, + {"fixup_AAP_BR32", 0, 9, 0}, + {"fixup_AAP_BRCC16", 6, 3, 0}, + {"fixup_AAP_BRCC32", 6, 3, 0}, + {"fixup_AAP_BAL16", 0, 3, 0}, + {"fixup_AAP_BAL32", 0, 3, 0}, + {"fixup_AAP_ABS6", 0, 3, 0}, + {"fixup_AAP_ABS9", 0, 3, 0}, + {"fixup_AAP_ABS10", 0, 3, 0}, + {"fixup_AAP_ABS12", 0, 6, 0}, + {"fixup_AAP_ABS16", 0, 6, 0}, + {"fixup_AAP_SHIFT6", 0, 3, 0}, + {"fixup_AAP_OFF10", 0, 3, 0} + }; + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; + } + + +//===-------------------------- Fixup processing --------------------------===// + + + void applyFixup(MCFixup const &Fixup, char *Data, unsigned DataSize, + uint64_t Value, bool IsPCRel) const override { + // No target specific fixups are applied in the backend as they are all + // handled as relocations in the linker. + // Generic relocations are handled, as they may be literal values which + // need to be resolved before they reach the linker. + unsigned Size = 0; + switch ((unsigned)Fixup.getKind()) { + case FK_Data_1: Size = 1; break; + case FK_Data_2: Size = 2; break; + case FK_Data_4: Size = 4; break; + case FK_Data_8: Size = 8; break; + default: + return; + } + for (unsigned i = 0; i < Size; ++i) { + Data[i + Fixup.getOffset()] = static_cast(Value >> (i * 8)); + } + return; + } + + void processFixupValue(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFixup &Fixup, + const MCFragment *DF, + const MCValue &Target, + uint64_t &Value, + bool &isResolved) override { + // No AAP specific fixups are processed in the backend. + switch ((unsigned)Fixup.getKind()) { + case FK_Data_1: + case FK_Data_2: + case FK_Data_4: + case FK_Data_8: + isResolved = true; + default: + return; + } + isResolved = false; + } + + +//===------------------------ Relaxation interface ------------------------===// + + + bool mayNeedRelaxation(MCInst const &Inst) const override { + // We already generate the longest instruction necessary, so there is + // nothing to relax. + return false; + } + + bool fixupNeedsRelaxation(MCFixup const &Fixup, uint64_t Value, + MCRelaxableFragment const *DF, + MCAsmLayout const &Layout) const override { + // We already generate the longest instruction necessary so there is + // no need to relax, and at the moment we should never see fixups for + // short instructions. + switch ((unsigned)Fixup.getKind()) { + case AAP::fixup_AAP_BR16: + case AAP::fixup_AAP_BRCC16: + case AAP::fixup_AAP_BAL16: + llvm_unreachable("Cannot relax short instruction fixups!"); + default: + return false; + } + } + + void relaxInstruction(MCInst const &Inst, MCInst &Res) const override { + // The only instructions which should require relaxation are short + // instructions with fixups, and at the moment these instructions should + // not be selected or parsed + llvm_unreachable("Unexpected short instruction with fixup"); + } + + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override { + if ((Count % 2) != 0) { + return false; + } + + // 0x0001 corresponds to nop $r0, 1 + for (uint64_t i = 0; i < Count; i += 2) { + OW->write16(0x0001); + } + return true; + } +}; +} // end anonymous namespace + + +namespace { +class ELFAAPAsmBackend : public AAPAsmBackend { + uint8_t OSABI; + +public: + ELFAAPAsmBackend(Target const &T, uint8_t OSABI) + : AAPAsmBackend(T), OSABI(OSABI) {} + + MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { + StringRef CPU("Default"); + return createAAPELFObjectWriter(OS, OSABI, CPU); + } +}; +} // end anonymous namespace + + +namespace llvm { +MCAsmBackend *createAAPAsmBackend(Target const &T, MCRegisterInfo const &MRI, + const Triple &TT, StringRef CPU) { + uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(Triple(TT).getOS()); + return new ELFAAPAsmBackend(T, OSABI); +} +} Index: lib/Target/AAP/MCTargetDesc/AAPELFObjectWriter.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/AAPELFObjectWriter.cpp @@ -0,0 +1,82 @@ +//===-- AAPELFObjectWriter.cpp - AAP Target Descriptions ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AAP.h" +#include "MCTargetDesc/AAPFixupKinds.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "aap-elfwriter" + +using namespace llvm; + +namespace { + +class AAPELFObjectWriter : public MCELFObjectTargetWriter { +private: + StringRef CPU; + +public: + AAPELFObjectWriter(uint8_t OSABI, StringRef C); + + unsigned getRelocType(MCContext &Ctx, MCValue const &Target, + MCFixup const &Fixup, bool IsPCRel) const override; +}; +} + +AAPELFObjectWriter::AAPELFObjectWriter(uint8_t OSABI, StringRef C) + : MCELFObjectTargetWriter(/*Is64bit*/ false, OSABI, ELF::EM_AAP, + /*HasRelocationAddend*/ true), + CPU(C) {} + +unsigned AAPELFObjectWriter::getRelocType(MCContext & /*Ctx*/, + MCValue const & /*Target*/, + MCFixup const &Fixup, + bool IsPCRel) const { + llvm::MCFixupKind Kind = Fixup.getKind(); + + switch ((unsigned)Kind) { + case AAP::fixup_AAP_NONE: return ELF::R_AAP_NONE; + case AAP::fixup_AAP_BR32: return ELF::R_AAP_BR32; + case AAP::fixup_AAP_BRCC32: return ELF::R_AAP_BRCC32; + case AAP::fixup_AAP_BAL32: return ELF::R_AAP_BAL32; + + case AAP::fixup_AAP_ABS6: return ELF::R_AAP_ABS6; + case AAP::fixup_AAP_ABS9: return ELF::R_AAP_ABS9; + case AAP::fixup_AAP_ABS10: return ELF::R_AAP_ABS10; + case AAP::fixup_AAP_ABS12: return ELF::R_AAP_ABS12; + case AAP::fixup_AAP_ABS16: return ELF::R_AAP_ABS16; + + case AAP::fixup_AAP_SHIFT6: return ELF::R_AAP_SHIFT6; + case AAP::fixup_AAP_OFF10: return ELF::R_AAP_OFF10; + + case FK_Data_1: return ELF::R_AAP_8; + case FK_Data_2: return ELF::R_AAP_16; + case FK_Data_4: return ELF::R_AAP_32; + case FK_Data_8: return ELF::R_AAP_64; + + // Instrs with these fixups should never be generated or parsed, so for now + // we should not be emitting relocations for them. + case AAP::fixup_AAP_BR16: + case AAP::fixup_AAP_BRCC16: + case AAP::fixup_AAP_BAL16: + llvm_unreachable("Cannot emit relocations for short instruction fixups!"); + default: + llvm_unreachable("Unimplemented fixup kind!"); + } + return ELF::R_AAP_NONE; +} + +MCObjectWriter *llvm::createAAPELFObjectWriter(raw_pwrite_stream &OS, + uint8_t OSABI, StringRef CPU) { + MCELFObjectTargetWriter *MOTW = new AAPELFObjectWriter(OSABI, CPU); + return createELFObjectWriter(MOTW, OS, /*IsLittleEndian*/ true); +} Index: lib/Target/AAP/MCTargetDesc/AAPFixupKinds.h =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/AAPFixupKinds.h @@ -0,0 +1,58 @@ +//===-- AAPFixupKinds.h - AAP Specific Fixup Entries ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_AAP_AAPFIXUPKINDS_H +#define LLVM_AAP_AAPFIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +namespace llvm { +namespace AAP { +// Although most of the current fixup types reflect a unique relocation +// one can have multiple fixup types for a given relocation and thus need +// to be uniquely named. +// +// This table *must* be in the save order of +// MCFixupKindInfo Infos[AAP::NumTargetFixupKinds] +// in AAPAsmBackend.cpp. +// +enum Fixups { + // Results in R_AAP_NONE + fixup_AAP_NONE = FirstTargetFixupKind, + + // Fixup for resolving branches to other basic blocks + fixup_AAP_BR16, + fixup_AAP_BR32, + + // Fixup for resolving conditional branches to other basic blocks + fixup_AAP_BRCC16, + fixup_AAP_BRCC32, + + // Branch and link fixups + fixup_AAP_BAL16, + fixup_AAP_BAL32, + + // Fixup for absolute values + fixup_AAP_ABS6, + fixup_AAP_ABS9, + fixup_AAP_ABS10, + fixup_AAP_ABS12, + fixup_AAP_ABS16, + + // Shift and offset fixups + fixup_AAP_SHIFT6, + fixup_AAP_OFF10, + + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind +}; +} // end namespace AAP +} // end namespace llvm + +#endif Index: lib/Target/AAP/MCTargetDesc/AAPMCAsmInfo.h =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/AAPMCAsmInfo.h @@ -0,0 +1,32 @@ +//===-- AAPMCAsmInfo.h - AAP asm properties --------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the AAPMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_AAP_MCTARGETDESC_AAPMCASMINFO_H +#define LLVM_LIB_TARGET_AAP_MCTARGETDESC_AAPMCASMINFO_H + +#include "llvm/MC/MCAsmInfoELF.h" +#include "llvm/ADT/Triple.h" + +namespace llvm { +class StringRef; + +class AAPMCAsmInfo : public MCAsmInfoELF { + void anchor() override; + +public: + explicit AAPMCAsmInfo(const Triple &TT); +}; + +} // namespace llvm + +#endif Index: lib/Target/AAP/MCTargetDesc/AAPMCAsmInfo.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/AAPMCAsmInfo.cpp @@ -0,0 +1,27 @@ +//===-- AAPMCAsmInfo.cpp - AAP asm properties -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the AAPMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "AAPMCAsmInfo.h" +#include "llvm/ADT/Triple.h" + +using namespace llvm; + +void AAPMCAsmInfo::anchor() {} + +AAPMCAsmInfo::AAPMCAsmInfo(const llvm::Triple &TT) { + CalleeSaveStackSlotSize = 2; + PointerSize = 4; + CommentString = ";"; + SupportsDebugInformation = true; + UsesELFSectionDirectiveForBSS = true; +} Index: lib/Target/AAP/MCTargetDesc/AAPMCCodeEmitter.h =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/AAPMCCodeEmitter.h @@ -0,0 +1,97 @@ +//===-- AAPMCCodeEmitter.h - AAP Code Emitter -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Definition for classes that emit AAP machine code from MCInsts +/// +//===----------------------------------------------------------------------===// + +#ifndef AAPMCCODEEMITTER_H +#define AAPMCCODEEMITTER_H + +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +class AAPMCCodeEmitter : public MCCodeEmitter { + MCContext &MCtx; + MCInstrInfo const &MCII; + +public: + AAPMCCodeEmitter(MCInstrInfo const &aMII, MCContext &aMCT); + + MCSubtargetInfo const &getSubtargetInfo() const; + + void encodeInstruction(MCInst const &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const override; + + unsigned encodePCRelImmOperand(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned encodeMemSrcOperand(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + + unsigned encodeImmN(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI, + MCFixupKind FixupKind) const; + unsigned encodeImm3(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + unsigned encodeImm6(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + unsigned encodeImm9(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + unsigned encodeImm10(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + unsigned encodeImm12(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + + unsigned encodeField16(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + + unsigned encodeShiftConst3(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + unsigned encodeShiftImm6(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + + // TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(MCInst const &MI, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + + /// Return binary encoding of operand. + unsigned getMachineOpValue(MCInst const &MI, MCOperand const &MO, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const; + +private: + AAPMCCodeEmitter(AAPMCCodeEmitter const &) = delete; + void operator=(AAPMCCodeEmitter const &) = delete; +}; // class AAPMCCodeEmitter + +} // namespace llvm + +#endif /* AAPMCCODEEMITTER_H */ Index: lib/Target/AAP/MCTargetDesc/AAPMCCodeEmitter.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/AAPMCCodeEmitter.cpp @@ -0,0 +1,283 @@ +//===-- AAPMCCodeEmitter.cpp - AAP Target Descriptions --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AAP.h" +#include "MCTargetDesc/AAPFixupKinds.h" +#include "MCTargetDesc/AAPMCCodeEmitter.h" +#include "MCTargetDesc/AAPMCTargetDesc.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "aap-codemitter" + +using namespace llvm; +using namespace AAP; + +STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); + +namespace { +void emitLittleEndian(uint64_t Encoding, raw_ostream &OS, unsigned sz) { + while (sz > 0) { + OS << static_cast(Encoding & 0xff); + Encoding = Encoding >> 8; + sz--; + } +} +} + +AAPMCCodeEmitter::AAPMCCodeEmitter(MCInstrInfo const &MII, MCContext &Context) + : MCtx(Context), MCII(MII) {} + +void AAPMCCodeEmitter::encodeInstruction(MCInst const &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const { + const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); + uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI); + emitLittleEndian(Binary, OS, Desc.getSize()); + ++MCNumEmitted; +} + +unsigned AAPMCCodeEmitter::getMachineOpValue(MCInst const &MI, + MCOperand const &MO, + SmallVectorImpl &Fixups, + MCSubtargetInfo const &STI) const { + if (MO.isReg()) + return MCtx.getRegisterInfo()->getEncodingValue(MO.getReg()); + if (MO.isImm()) + return static_cast(MO.getImm()); + + // MO must be an expression + assert(MO.isExpr()); + + const MCExpr *Expr = MO.getExpr(); + MCExpr::ExprKind Kind = Expr->getKind(); + + if (Kind == MCExpr::Binary) { + Expr = static_cast(Expr)->getLHS(); + Kind = Expr->getKind(); + } + + assert(Kind == MCExpr::SymbolRef); + + AAP::Fixups FixupKind = AAP::Fixups(0); + const unsigned Opcode = MI.getOpcode(); + if (Opcode == AAP::BAL) { + FixupKind = AAP::fixup_AAP_BAL32; + } else if (Opcode == AAP::BAL_short) { + FixupKind = AAP::fixup_AAP_BAL16; + } else { + llvm_unreachable("Unknown fixup kind!"); + } + + // Push fixup, encoding 0 as the current operand + Fixups.push_back( + MCFixup::create(0, MO.getExpr(), MCFixupKind(FixupKind), MI.getLoc())); + return 0; +} + +MCCodeEmitter *llvm::createAAPMCCodeEmitter(MCInstrInfo const &MII, + MCRegisterInfo const &MRI, + MCContext &Context) { + return new AAPMCCodeEmitter(MII, Context); +} + +// TODO: Better way than using LUTs? +static const unsigned BRCCOpcodes[] = { + AAP::BEQ_, AAP::BNE_, AAP::BLTS_, + AAP::BLES_, AAP::BLTU_, AAP::BLEU_, + + AAP::BEQ_short, AAP::BNE_short, AAP::BLTS_short, + AAP::BLES_short, AAP::BLTU_short, AAP::BLEU_short +}; + +static bool findOpcode(unsigned Op, ArrayRef Opcodes) { + for (auto It = Opcodes.begin(); It != Opcodes.end(); It++) { + if (Op == *It) { + return true; + } + } + return false; +} + +unsigned +AAPMCCodeEmitter::encodePCRelImmOperand(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(Op); + if (MO.isReg() || MO.isImm()) { + return getMachineOpValue(MI, MO, Fixups, STI); + } + + const unsigned Opcode = MI.getOpcode(); + AAP::Fixups FixupKind; + switch (Opcode) { + case AAP::BRA: + FixupKind = AAP::fixup_AAP_BR32; + break; + case AAP::BRA_short: + FixupKind = AAP::fixup_AAP_BR16; + break; + case AAP::BAL: + FixupKind = AAP::fixup_AAP_BAL32; + break; + case AAP::BAL_short: + FixupKind = AAP::fixup_AAP_BAL16; + break; + default: + FixupKind = AAP::fixup_AAP_NONE; + if (findOpcode(Opcode, BRCCOpcodes)) { + const MCInstrDesc &Desc = MCII.get(Opcode); + if (Desc.getSize() == 4) { + FixupKind = AAP::fixup_AAP_BRCC32; + } else { + FixupKind = AAP::fixup_AAP_BRCC16; + } + } else { + llvm_unreachable("Cannot encode fixup for non-branch pc-relative imm"); + } + } + Fixups.push_back(MCFixup::create(0, MO.getExpr(), (MCFixupKind)FixupKind)); + return 0; +} + +unsigned +AAPMCCodeEmitter::encodeMemSrcOperand(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + unsigned encoding; + + // Map register number to its encoding, encode in upper 16 bits + const MCOperand RegOp = MI.getOperand(Op); + assert(RegOp.isReg() && "First operand is not a register!"); + + unsigned Reg = MCtx.getRegisterInfo()->getEncodingValue(RegOp.getReg()); + encoding = (Reg & 0xffff) << 16; + + // Immediates map directly to their encoding, map into lower 16 bits + MCOperand ImmOp = MI.getOperand(Op + 1); + if (ImmOp.isImm()) { + encoding |= static_cast(ImmOp.getImm()) & 0xffff; + return encoding; + } + + // Not an immediate, check for an expression and store as fixup to be + // resolved later + assert(ImmOp.isExpr() && "Second memsrc op not an immediate or expression!"); + + const unsigned Opcode = MI.getOpcode(); + const MCInstrDesc &Desc = MCII.get(Opcode); + assert(Desc.getSize() == 4 && + "Cannot encode an expression in a short memory+offset operand"); + + AAP::Fixups FixupKind = AAP::fixup_AAP_OFF10; + Fixups.push_back(MCFixup::create(0, ImmOp.getExpr(), MCFixupKind(FixupKind))); + return encoding; +} + +// Try to encode an immediate directly. If that is not possible then emit a +// provided fixup kind. +// +// The FixupKind is assumed to be a AAP specific fixup, if it is not then it +// signifies that a fixup cannot be emitted for the provided immediate. +unsigned AAPMCCodeEmitter::encodeImmN(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI, + MCFixupKind FixupKind) const { + const MCOperand MO = MI.getOperand(Op); + if (MO.isImm()) { + return static_cast(MO.getImm()); + } + assert(MO.isExpr()); + assert(MCII.get(MI.getOpcode()).getSize() == 4 && + "Cannot encode fixups for short instruction immediates"); + + if (FixupKind >= FirstTargetFixupKind) { + Fixups.push_back(MCFixup::create(0, MO.getExpr(), FixupKind)); + } else { + llvm_unreachable("Cannot encode a fixup for this immediate operand"); + } + return 0; +} + +unsigned AAPMCCodeEmitter::encodeImm3(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + return encodeImmN(MI, Op, Fixups, STI, static_cast(0)); +} + +unsigned AAPMCCodeEmitter::encodeImm6(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + return encodeImmN(MI, Op, Fixups, STI, MCFixupKind(AAP::fixup_AAP_ABS6)); +} + +unsigned AAPMCCodeEmitter::encodeImm9(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + return encodeImmN(MI, Op, Fixups, STI, MCFixupKind(AAP::fixup_AAP_ABS9)); +} + +unsigned AAPMCCodeEmitter::encodeImm10(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + return encodeImmN(MI, Op, Fixups, STI, MCFixupKind(AAP::fixup_AAP_ABS10)); +} + +unsigned AAPMCCodeEmitter::encodeImm12(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + return encodeImmN(MI, Op, Fixups, STI, MCFixupKind(AAP::fixup_AAP_ABS12)); +} + +unsigned AAPMCCodeEmitter::encodeField16(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + return encodeImmN(MI, Op, Fixups, STI, MCFixupKind(AAP::fixup_AAP_ABS16)); +} + +unsigned AAPMCCodeEmitter::encodeShiftConst3(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand MO = MI.getOperand(Op); + if (MO.isImm()) { + // Subtract one to get the actual encoding of the shift value + unsigned value = MO.getImm(); + return static_cast(value - 1); + } else { + llvm_unreachable("Cannot encode an expression in a short shift operand"); + } + return 0; +} + +unsigned AAPMCCodeEmitter::encodeShiftImm6(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand MO = MI.getOperand(Op); + if (MO.isImm()) { + // Subtract one to get the actual encoding of the shift value + unsigned value = MO.getImm(); + return static_cast(value - 1); + } + assert(MO.isExpr()); + AAP::Fixups FixupKind = AAP::fixup_AAP_SHIFT6; + Fixups.push_back(MCFixup::create(0, MO.getExpr(), MCFixupKind(FixupKind))); + return 0; +} + + +#include "AAPGenMCCodeEmitter.inc" Index: lib/Target/AAP/MCTargetDesc/AAPMCTargetDesc.h =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/AAPMCTargetDesc.h @@ -0,0 +1,57 @@ +//===-- AAPMCTargetDesc.h - AAP Target Descriptions -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides AAP specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_AAP_MCTARGETDESC_AAPMCTARGETDESC_H +#define LLVM_LIB_TARGET_AAP_MCTARGETDESC_AAPMCTARGETDESC_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectWriter; +class MCRegisterInfo; +class StringRef; +class Target; +class Triple; +class raw_pwrite_stream; + +extern Target TheAAPTarget; + +MCCodeEmitter *createAAPMCCodeEmitter(MCInstrInfo const &MCII, + MCRegisterInfo const &MRI, + MCContext &Context); + +MCAsmBackend *createAAPAsmBackend(Target const &T, MCRegisterInfo const &MRI, + const Triple &TT, StringRef CPU); + +MCObjectWriter *createAAPELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI, + StringRef CPU); + +} // End llvm namespace + +// Defines symbolic names for AAP registers. +// This defines a mapping from register name to register number. +#define GET_REGINFO_ENUM +#include "AAPGenRegisterInfo.inc" + +// Defines symbolic names for the AAP instructions. +#define GET_INSTRINFO_ENUM +#include "AAPGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "AAPGenSubtargetInfo.inc" + +#endif Index: lib/Target/AAP/MCTargetDesc/AAPMCTargetDesc.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/AAPMCTargetDesc.cpp @@ -0,0 +1,95 @@ +//===-- AAPMCTargetDesc.cpp - AAP Target Descriptions ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides AAP specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "AAPMCTargetDesc.h" +#include "InstPrinter/AAPInstPrinter.h" +#include "AAPRegisterInfo.h" +#include "AAPMCAsmInfo.h" +#include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define GET_INSTRINFO_MC_DESC +#include "AAPGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "AAPGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "AAPGenRegisterInfo.inc" + +static MCInstrInfo *createAAPMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitAAPMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createAAPMCRegisterInfo(const Triple &TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitAAPMCRegisterInfo(X, AAP::R0); + return X; +} + +static MCSubtargetInfo *createAAPMCSubtargetInfo(const Triple &TT, + StringRef CPU, StringRef FS) { + return createAAPMCSubtargetInfoImpl(TT, CPU, FS); +} + +static MCCodeGenInfo *createAAPMCCodeGenInfo(const Triple &TT, Reloc::Model RM, + CodeModel::Model CM, + CodeGenOpt::Level OL) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + X->initMCCodeGenInfo(RM, CM, OL); + return X; +} + +static MCInstPrinter *createAAPMCInstPrinter(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + if (SyntaxVariant == 0) + return new AAPInstPrinter(MAI, MII, MRI); + return nullptr; +} + +extern "C" void LLVMInitializeAAPTargetMC() { + // Register the MC asm info. + RegisterMCAsmInfo X(TheAAPTarget); + + // Register the MC codegen info. + TargetRegistry::RegisterMCCodeGenInfo(TheAAPTarget, createAAPMCCodeGenInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(TheAAPTarget, createAAPMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(TheAAPTarget, createAAPMCRegisterInfo); + + // Register the MC Code Emitter + TargetRegistry::RegisterMCCodeEmitter(TheAAPTarget, createAAPMCCodeEmitter); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(TheAAPTarget, + createAAPMCSubtargetInfo); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(TheAAPTarget, createAAPMCInstPrinter); + + // Register the asm backend + TargetRegistry::RegisterMCAsmBackend(TheAAPTarget, createAAPAsmBackend); +} Index: lib/Target/AAP/MCTargetDesc/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,7 @@ +add_llvm_library(LLVMAAPDesc + AAPAsmBackend.cpp + AAPELFObjectWriter.cpp + AAPMCAsmInfo.cpp + AAPMCCodeEmitter.cpp + AAPMCTargetDesc.cpp + ) Index: lib/Target/AAP/MCTargetDesc/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/AAP/MCTargetDesc/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/AAP/MCTargetDesc/LLVMBuild.txt --------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = AAPDesc +parent = AAP +required_libraries = MC Support AAPAsmPrinter AAPInfo +add_to_library_groups = AAP Index: lib/Target/AAP/TargetInfo/AAPTargetInfo.cpp =================================================================== --- /dev/null +++ lib/Target/AAP/TargetInfo/AAPTargetInfo.cpp @@ -0,0 +1,19 @@ +//===-- AAPTargetInfo.cpp - AAP Target Implementation ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AAP.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheAAPTarget; + +extern "C" void LLVMInitializeAAPTargetInfo() { + RegisterTarget X(TheAAPTarget, "aap", "AAP [experimental]"); +} Index: lib/Target/AAP/TargetInfo/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/AAP/TargetInfo/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMAAPInfo + AAPTargetInfo.cpp + ) Index: lib/Target/AAP/TargetInfo/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/AAP/TargetInfo/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/AAP/TargetInfo/LLVMBuild.txt ----------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = AAPInfo +parent = AAP +required_libraries = Support +add_to_library_groups = AAP Index: lib/Target/AAPSimulator/AAPSimulator.h =================================================================== --- /dev/null +++ lib/Target/AAPSimulator/AAPSimulator.h @@ -0,0 +1,61 @@ +//===-- AAPSimulator.h - AAP Simulator -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a definition of a simulated AAP +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_AAPSIMULATOR_AAPSIMULATOR_H +#define LLVM_LIB_TARGET_AAPSIMULATOR_AAPSIMULATOR_H + +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/TargetRegistry.h" +#include "AAPSimState.h" + +namespace AAPSim { + +/// AAPSimulator - AAP Simulator +class AAPSimulator { + AAPSimState State; + + // Target/MCInfo + const llvm::Target *TheTarget; + const llvm::MCRegisterInfo *MRI; + const llvm::MCAsmInfo *AsmInfo; + const llvm::MCSubtargetInfo *STI; + const llvm::MCInstrInfo *MII; + llvm::MCDisassembler *DisAsm; + llvm::MCInstPrinter *IP; + +public: + AAPSimulator(); + + AAPSimState &getState() { return State; } + + /// Functions for writing bulk to the code/data memories + void WriteCodeSection(llvm::StringRef Bytes, uint32_t address); + void WriteDataSection(llvm::StringRef Bytes, uint32_t address); + + /// Set Program Counter + void setPC(uint32_t pc_w) { State.setPC(pc_w); } + + /// Execute an instruction + SimStatus exec(llvm::MCInst &Inst, uint32_t pc_w, uint32_t &newpc_w); + + /// Step the processor + SimStatus step(); +}; + +} // End AAPSim namespace + +#endif Index: lib/Target/AAPSimulator/AAPSimulator.cpp =================================================================== --- /dev/null +++ lib/Target/AAPSimulator/AAPSimulator.cpp @@ -0,0 +1,693 @@ +//===-- AAPSimulator.cpp - AAP Simulator ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides an implementation of a simulated AAP +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/TargetRegistry.h" +#include "AAPSimulator.h" +#include + +#define GET_INSTRINFO_ENUM +#include "AAPGenInstrInfo.inc" + +#define GET_REGINFO_ENUM +#include "AAPGenRegisterInfo.inc" + +using namespace llvm; +using namespace AAPSim; + +static cl::opt Trace("trace"); + +// Should the simulator call llvm_unreachable when executing unknown +#define UNKNOWN_SHOULD_UNREACHABLE 0 + +// Register and memory exception handlers +#define EXCEPT(x) x; if (State.getStatus() != SimStatus::SIM_OK) return State.getStatus() + +AAPSimulator::AAPSimulator() { + std::string Error; + TheTarget = TargetRegistry::lookupTarget("aap-none-none", Error); + if (!TheTarget) { + errs() << "aap-run: " << Error << "\n"; + } + + // Set up all MC/Target components needed by the disassembler + MRI = TheTarget->createMCRegInfo("aap-none-none"); + if (!MRI) { + errs() << "error: no register info\n"; + return; + } + + AsmInfo = TheTarget->createMCAsmInfo(*MRI, "aap-none-none"); + if (!AsmInfo) { + errs() << "error: no asminfo\n"; + return; + } + + STI = TheTarget->createMCSubtargetInfo("aap-none-none", "", ""); + if (!STI) { + errs() << "error: no subtarget info\n"; + return; + } + + MII = TheTarget->createMCInstrInfo(); + if (!MII) { + errs() << "error: no instruction info\n"; + return; + } + + const MCObjectFileInfo *MOFI = new MCObjectFileInfo(); + MCContext Ctx(AsmInfo, MRI, MOFI); + + DisAsm = TheTarget->createMCDisassembler(*STI, Ctx); + if (!DisAsm) { + errs() << "error: no disassembler\n"; + return; + } + + int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); + IP = TheTarget->createMCInstPrinter( + Triple("aap-none-none"), AsmPrinterVariant, *AsmInfo, *MII, *MRI); + if (!IP) { + errs() << "error: no instruction printer\n"; + return; + } +} + +void AAPSimulator::WriteCodeSection(llvm::StringRef Bytes, uint32_t address) { + for (size_t i = 0; i < Bytes.size(); i++) { + State.setCodeMem(address + i, Bytes[i]); + } +} + +void AAPSimulator::WriteDataSection(llvm::StringRef Bytes, uint32_t address) { + for (size_t i = 0; i < Bytes.size(); i++) { + State.setDataMem(address + i, Bytes[i]); + } +} + +static int getLLVMReg(unsigned Reg) { + switch (Reg) { + default: llvm_unreachable("Invalid register"); +#define REG(x) case AAP::R##x: return x; + REG(0) REG(1) REG(2) REG(3) REG(4) REG(5) REG(6) REG(7) + REG(8) REG(9) REG(10) REG(11) REG(12) REG(13) REG(14) REG(15) + REG(16) REG(17) REG(18) REG(19) REG(20) REG(21) REG(22) REG(23) + REG(24) REG(25) REG(26) REG(27) REG(28) REG(29) REG(30) REG(31) + REG(32) REG(33) REG(34) REG(35) REG(36) REG(37) REG(38) REG(39) + REG(40) REG(41) REG(42) REG(43) REG(44) REG(45) REG(46) REG(47) + REG(48) REG(49) REG(50) REG(51) REG(52) REG(53) REG(54) REG(55) + REG(56) REG(57) REG(58) REG(59) REG(60) REG(61) REG(62) REG(63) +#undef REG + } +} + +// Function to sign extend a uint16_t register for detecting overflow +static uint32_t signExtend16(uint16_t val) { + uint32_t newval = static_cast(val); + uint32_t sign = newval & 0x8000; + if (sign) + newval |= 0xffff0000; + return newval; +} + +// Sign extend branch cc target (long, 10 bits) +static int16_t signExtendBranchCC(uint16_t val) { + if (val & 0x0200) + val |= 0xfc00; + return static_cast(val); +} + +// Sign extend branch target (long, 18 bits) +static int32_t signExtendBranch(uint32_t val) { + if (val & 0x00020000) + val |= 0xfffc0000; + return static_cast(val); +} + +// Sign extend branch target (short, 9 bits) +static int16_t signExtendBranchS(uint16_t val) { + if (val & 0x100) + val |= 0xfe00; + return static_cast(val); +} + +// Sign extend branch and link target (short, 6 bits) +static int16_t signExtendBranchAndLinkS(uint16_t val) { + if (val & 0x20) + val |= 0xffc0; + return static_cast(val); +} + +// Sign extend branch conditional target (short, 6 bits) +static int16_t signExtendBranchCCS(uint16_t val) { + return signExtendBranchAndLinkS(val); +} + +SimStatus AAPSimulator::exec(MCInst &Inst, uint32_t pc_w, uint32_t &newpc_w) { + switch (Inst.getOpcode()) { + // Unknown instruction + default: +#if UNKNOWN_SHOULD_UNREACHABLE + llvm_unreachable("No simulator support for this instruction"); +#else + newpc_w = pc_w; + return SimStatus::SIM_TRAP; +#endif + break; + + // NOP Handling + // 0: Breakpoint + // 1: NOP + // 2: Exit with retcode in Rd + // 3: Write char Rd to stdout + // 4: Write char Rd to stderr + case AAP::NOP: + case AAP::NOP_short: { + int Reg = getLLVMReg(Inst.getOperand(0).getReg()); + uint16_t Command = Inst.getOperand(1).getImm(); + // Load register value and char for NOPs that require it + EXCEPT(uint16_t RegVal = State.getReg(Reg)); + char c = static_cast(RegVal); + switch (Command) { + case 0: return SimStatus::SIM_BREAKPOINT; + default: // Treat unknown values as NOP + case 1: break; + case 2: + State.setExitCode(RegVal); + return SimStatus::SIM_QUIT; + case 3: + outs() << c; + break; + case 4: + errs() << c; + break; + } + break; + } + + // Move Instructions + case AAP::MOV_r: + case AAP::MOV_r_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrc = getLLVMReg(Inst.getOperand(1).getReg()); + EXCEPT(State.setReg(RegDst, State.getReg(RegSrc))); + break; + } + case AAP::MOVI_i16: + case AAP::MOVI_i6_short: { + int Reg = getLLVMReg(Inst.getOperand(0).getReg()); + uint16_t Val = Inst.getOperand(1).getImm() & 0xffff; + EXCEPT(State.setReg(Reg, Val)); + break; + } + + // ADD + case AAP::ADD_r: + case AAP::ADD_r_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + int RegSrcB = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(uint32_t ValA = signExtend16(State.getReg(RegSrcA))); + EXCEPT(uint32_t ValB = signExtend16(State.getReg(RegSrcB))); + uint32_t Res = ValA + ValB; + EXCEPT(State.setReg(RegDst, static_cast(Res))); + // Test for overflow + int32_t Res_s = static_cast(Res); + State.setOverflow(static_cast(Res_s) != Res_s ? 1 : 0); + break; + } + + // ADDC + case AAP::ADDC_r: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + int RegSrcB = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(uint32_t ValA = signExtend16(State.getReg(RegSrcA))); + EXCEPT(uint32_t ValB = signExtend16(State.getReg(RegSrcB))); + uint32_t Res = ValA + ValB + State.getOverflow(); + EXCEPT(State.setReg(RegDst, static_cast(Res))); + // Test for overflow + int32_t Res_s = static_cast(Res); + State.setOverflow(static_cast(Res_s) != Res_s ? 1 : 0); + break; + } + + // ADDI + case AAP::ADDI_i10: + case AAP::ADDI_i3_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + EXCEPT(uint32_t ValA = signExtend16(State.getReg(RegSrcA))); + uint32_t ValB = Inst.getOperand(2).getImm(); + uint32_t Res = ValA + ValB; + EXCEPT(State.setReg(RegDst, static_cast(Res))); + // Test for overflow + int32_t Res_s = static_cast(Res); + State.setOverflow(static_cast(Res_s) != Res_s ? 1 : 0); + break; + } + + // SUB + case AAP::SUB_r: + case AAP::SUB_r_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + int RegSrcB = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(uint32_t ValA = signExtend16(State.getReg(RegSrcA))); + EXCEPT(uint32_t ValB = signExtend16(State.getReg(RegSrcB))); + uint32_t Res = ValA - ValB; + EXCEPT(State.setReg(RegDst, static_cast(Res))); + // Test for overflow + int32_t Res_s = static_cast(Res); + State.setOverflow(static_cast(Res_s) != Res_s ? 1 : 0); + break; + } + + // SUBC + case AAP::SUBC_r: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + int RegSrcB = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(uint32_t ValA = signExtend16(State.getReg(RegSrcA))); + EXCEPT(uint32_t ValB = signExtend16(State.getReg(RegSrcB))); + uint32_t Res = ValA - ValB - State.getOverflow(); + EXCEPT(State.setReg(RegDst, static_cast(Res))); + // Test for overflow + int32_t Res_s = static_cast(Res); + State.setOverflow(static_cast(Res_s) != Res_s ? 1 : 0); + break; + } + + // SUBI + case AAP::SUBI_i10: + case AAP::SUBI_i3_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + EXCEPT(uint32_t ValA = signExtend16(State.getReg(RegSrcA))); + uint32_t ValB = Inst.getOperand(2).getImm(); + uint32_t Res = ValA - ValB; + EXCEPT(State.setReg(RegDst, static_cast(Res))); + // Test for overflow + int32_t Res_s = static_cast(Res); + State.setOverflow(static_cast(Res_s) != Res_s ? 1 : 0); + break; + } + + // AND + case AAP::AND_r: + case AAP::AND_r_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + int RegSrcB = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(uint16_t ValA = State.getReg(RegSrcA)); + EXCEPT(uint16_t ValB = State.getReg(RegSrcB)); + uint16_t Res = ValA & ValB; + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // ANDI + case AAP::ANDI_i9: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + EXCEPT(uint16_t ValA = State.getReg(RegSrcA)); + uint16_t ValB = Inst.getOperand(2).getImm(); + uint16_t Res = ValA & ValB; + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // OR + case AAP::OR_r: + case AAP::OR_r_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + int RegSrcB = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(uint16_t ValA = State.getReg(RegSrcA)); + EXCEPT(uint16_t ValB = State.getReg(RegSrcB)); + uint16_t Res = ValA | ValB; + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // ORI + case AAP::ORI_i9: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + EXCEPT(uint16_t ValA = State.getReg(RegSrcA)); + uint16_t ValB = Inst.getOperand(2).getImm(); + uint16_t Res = ValA | ValB; + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // XOR + case AAP::XOR_r: + case AAP::XOR_r_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + int RegSrcB = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(uint16_t ValA = State.getReg(RegSrcA)); + EXCEPT(uint16_t ValB = State.getReg(RegSrcB)); + uint16_t Res = ValA ^ ValB; + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // XORI + case AAP::XORI_i9: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + EXCEPT(uint16_t ValA = State.getReg(RegSrcA)); + uint16_t ValB = Inst.getOperand(2).getImm(); + uint16_t Res = ValA ^ ValB; + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // ASR + case AAP::ASR_r: + case AAP::ASR_r_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + int RegSrcB = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(int16_t ValA = static_cast(State.getReg(RegSrcA))); + EXCEPT(int16_t ValB = static_cast(State.getReg(RegSrcB) & 0xf)); + uint16_t Res = static_cast(ValA >> ValB); + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // ASRI + case AAP::ASRI_i6: + case AAP::ASRI_i3_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + EXCEPT(int16_t ValA = static_cast(State.getReg(RegSrcA))); + int16_t ValB = static_cast(Inst.getOperand(2).getImm() & 0xf); + uint16_t Res = static_cast(ValA >> ValB); + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // LSL + case AAP::LSL_r: + case AAP::LSL_r_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + int RegSrcB = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(uint16_t ValA = State.getReg(RegSrcA)); + EXCEPT(uint16_t ValB = State.getReg(RegSrcB) & 0xf); + uint16_t Res = ValA << ValB; + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // LSLI + case AAP::LSLI_i6: + case AAP::LSLI_i3_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + EXCEPT(uint16_t ValA = State.getReg(RegSrcA)); + uint16_t ValB = Inst.getOperand(2).getImm() & 0xf; + uint16_t Res = ValA << ValB; + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // LSR + case AAP::LSR_r: + case AAP::LSR_r_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + int RegSrcB = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(uint16_t ValA = State.getReg(RegSrcA)); + EXCEPT(uint16_t ValB = State.getReg(RegSrcB) & 0xf); + uint16_t Res = ValA >> ValB; + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // LSRI + case AAP::LSRI_i6: + case AAP::LSRI_i3_short: { + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegSrcA = getLLVMReg(Inst.getOperand(1).getReg()); + EXCEPT(uint16_t ValA = State.getReg(RegSrcA)); + EXCEPT(uint16_t ValB = Inst.getOperand(2).getImm() & 0xf); + uint16_t Res = ValA >> ValB; + EXCEPT(State.setReg(RegDst, Res)); + break; + } + + // Load + case AAP::LDB: + case AAP::LDB_short: + case AAP::LDW: + case AAP::LDW_short: + case AAP::LDB_postinc: + case AAP::LDB_postinc_short: + case AAP::LDW_postinc: + case AAP::LDW_postinc_short: + case AAP::LDB_predec: + case AAP::LDB_predec_short: + case AAP::LDW_predec: + case AAP::LDW_predec_short: { + bool postinc = (Inst.getOpcode() == AAP::LDB_postinc || + Inst.getOpcode() == AAP::LDB_postinc_short || + Inst.getOpcode() == AAP::LDW_postinc || + Inst.getOpcode() == AAP::LDW_postinc_short) ? true : false; + bool predec = (Inst.getOpcode() == AAP::LDB_predec || + Inst.getOpcode() == AAP::LDB_predec_short || + Inst.getOpcode() == AAP::LDW_predec || + Inst.getOpcode() == AAP::LDW_predec_short) ? true : false; + bool word = (Inst.getOpcode() == AAP::LDW || + Inst.getOpcode() == AAP::LDW_short || + Inst.getOpcode() == AAP::LDW_postinc || + Inst.getOpcode() == AAP::LDW_postinc_short || + Inst.getOpcode() == AAP::LDW_predec || + Inst.getOpcode() == AAP::LDW_predec_short) ? true : false; + // Initial register values + int RegDst = getLLVMReg(Inst.getOperand(0).getReg()); + int RegMem = getLLVMReg(Inst.getOperand(1).getReg()); + int Offset = Inst.getOperand(2).getImm(); + EXCEPT(uint16_t BaseAddress = State.getReg(RegMem)); + // Handle pre-dec + if (predec) { + BaseAddress -= Offset; + EXCEPT(State.setReg(RegMem, BaseAddress)); + Offset = 0; // No longer need to add offset for real load + } + EXCEPT(State.setReg(RegMem, BaseAddress)); + // Load, without adding offset if postincrement + uint16_t Address = BaseAddress; + if (!postinc) + Address += Offset; + EXCEPT(uint16_t Val = State.getDataMem(Address)); + if (word) + EXCEPT(Val |= State.getDataMem(Address + 1) << 8); + EXCEPT(State.setReg(RegDst, Val)); + // Handle post-inc + if (postinc) { + BaseAddress += Offset; + EXCEPT(State.setReg(RegMem, BaseAddress)); + } + break; + } + + // Store + case AAP::STB: + case AAP::STB_short: + case AAP::STW: + case AAP::STW_short: + case AAP::STB_postinc: + case AAP::STB_postinc_short: + case AAP::STW_postinc: + case AAP::STW_postinc_short: + case AAP::STB_predec: + case AAP::STB_predec_short: + case AAP::STW_predec: + case AAP::STW_predec_short: { + bool postinc = (Inst.getOpcode() == AAP::STB_postinc || + Inst.getOpcode() == AAP::STB_postinc_short || + Inst.getOpcode() == AAP::STW_postinc || + Inst.getOpcode() == AAP::STW_postinc_short) ? true : false; + bool predec = (Inst.getOpcode() == AAP::STB_predec || + Inst.getOpcode() == AAP::STB_predec_short || + Inst.getOpcode() == AAP::STW_predec || + Inst.getOpcode() == AAP::STW_predec_short) ? true : false; + bool word = (Inst.getOpcode() == AAP::STW || + Inst.getOpcode() == AAP::STW_short || + Inst.getOpcode() == AAP::STW_postinc || + Inst.getOpcode() == AAP::STW_postinc_short || + Inst.getOpcode() == AAP::STW_predec || + Inst.getOpcode() == AAP::STW_predec_short) ? true : false; + // Initial register values + int RegMem = getLLVMReg(Inst.getOperand(0).getReg()); + int Offset = Inst.getOperand(1).getImm(); + int RegSrc = getLLVMReg(Inst.getOperand(2).getReg()); + EXCEPT(uint16_t BaseAddress = State.getReg(RegMem)); + EXCEPT(uint16_t Val = State.getReg(RegSrc)); + // Handle pre-dec + if (predec) { + BaseAddress -= Offset; + EXCEPT(State.setReg(RegMem, BaseAddress)); + Offset = 0; // No longer need to add offset for real load + } + EXCEPT(State.setReg(RegMem, BaseAddress)); + // Store, without adding offset if postincrement + uint16_t Address = BaseAddress; + if (!postinc) + Address += Offset; + EXCEPT(State.setDataMem(Address, Val & 0xff)); + if (word) + EXCEPT(State.setDataMem(Address + 1, Val >> 8)); + // Handle post-inc + if (postinc) { + BaseAddress += Offset; + EXCEPT(State.setReg(RegMem, BaseAddress)); + } + break; + } + + // Branch and Link, Jump and Link + case AAP::BAL: + case AAP::BAL_short: + case AAP::JAL: + case AAP::JAL_short: { + int Reg = getLLVMReg(Inst.getOperand(1).getReg()); + EXCEPT(State.setReg(Reg, newpc_w)); + uint16_t Imm = Inst.getOperand(0).getImm(); + int16_t SImm = + (Inst.getOpcode() == AAP::BAL) ? static_cast(Imm) : + signExtendBranchAndLinkS(Imm); + if (Inst.getOpcode() == AAP::BAL || Inst.getOpcode() == AAP::BAL_short) + newpc_w = pc_w + SImm; + else + newpc_w = Imm; + break; + } + + // Conditional branches + case AAP::BEQ_: + case AAP::BEQ_short: + case AAP::BNE_: + case AAP::BNE_short: + case AAP::BLTS_: + case AAP::BLTS_short: + case AAP::BLES_: + case AAP::BLES_short: + case AAP::BLTU_: + case AAP::BLTU_short: + case AAP::BLEU_: + case AAP::BLEU_short: { + uint16_t Imm = Inst.getOperand(0).getImm(); + EXCEPT(uint16_t ValA = State.getReg(getLLVMReg(Inst.getOperand(1).getReg()))); + int16_t SValA = static_cast(ValA); + EXCEPT(uint16_t ValB = State.getReg(getLLVMReg(Inst.getOperand(2).getReg()))); + int16_t SValB = static_cast(ValB); + bool longbr = (Inst.getOpcode() == AAP::BEQ_ || + Inst.getOpcode() == AAP::BNE_ || + Inst.getOpcode() == AAP::BLTS_ || + Inst.getOpcode() == AAP::BLES_ || + Inst.getOpcode() == AAP::BLTU_ || + Inst.getOpcode() == AAP::BLEU_) ? true : false; + int16_t SImm = longbr ? signExtendBranchCC(Imm) + : signExtendBranchCCS(Imm); + bool branch = false; + // Decide whether to branch based on instruction type + if (Inst.getOpcode() == AAP::BEQ_ || Inst.getOpcode() == AAP::BEQ_short) + branch = (ValA == ValB) ? true : false; + if (Inst.getOpcode() == AAP::BNE_ || Inst.getOpcode() == AAP::BNE_short) + branch = (ValA != ValB) ? true : false; + if (Inst.getOpcode() == AAP::BLTS_ || Inst.getOpcode() == AAP::BLTS_short) + branch = (SValA < SValB) ? true : false; + if (Inst.getOpcode() == AAP::BLES_ || Inst.getOpcode() == AAP::BLES_short) + branch = (SValA <= SValB) ? true : false; + if (Inst.getOpcode() == AAP::BLTU_ || Inst.getOpcode() == AAP::BLTU_short) + branch = (ValA < ValB) ? true : false; + if (Inst.getOpcode() == AAP::BLEU_ || Inst.getOpcode() == AAP::BLEU_short) + branch = (ValA <= ValB) ? true : false; + // Branch if needed + if (branch) + newpc_w = pc_w + SImm; + break; + } + + // Branch + case AAP::BRA: + case AAP::BRA_short: { + uint32_t Offset = Inst.getOperand(0).getImm(); + int32_t SOffset = + (Inst.getOpcode() == AAP::BRA) ? signExtendBranch(Offset) + : signExtendBranchS(Offset); + newpc_w = pc_w + SOffset; + break; + } + + // Jump + case AAP::JMP: + case AAP::JMP_short: { + int Reg = getLLVMReg(Inst.getOperand(0).getReg()); + EXCEPT(newpc_w = State.getReg(Reg)); + break; + } + } // end opcode switch + + // By default, we exected the instruction + return SimStatus::SIM_OK; +} + +SimStatus AAPSimulator::step() { + MCInst Inst; + uint64_t Size; + uint32_t pc_w = State.getPC(); + ArrayRef *Bytes = State.getCodeArray(); + + // Reset any previous exception state + State.resetStatus(); + + if (DisAsm->getInstruction(Inst, Size, Bytes->slice(pc_w << 1), (pc_w << 1), + nulls(), nulls())) { + if (Trace) { + // Instruction decoded, execute it and write back our PC + dbgs() << format("%06" PRIx64 ":", pc_w); + IP->printInst(&Inst, dbgs(), "", *STI); + dbgs() << "\n"; + } + + uint32_t newpc_w = pc_w + (Size >> 1); + SimStatus status; + status = exec(Inst, pc_w, newpc_w); + State.setPC(newpc_w); + + return status; + } + else { + // Unable to read/decode an instruction. If the memory system threw an + // exception, pass this on, otherwise return invalid instruction. + if (State.getStatus() != SimStatus::SIM_OK) + return SimStatus::SIM_INVALID_INSN; + return State.getStatus(); + } +} Index: lib/Target/LLVMBuild.txt =================================================================== --- lib/Target/LLVMBuild.txt +++ lib/Target/LLVMBuild.txt @@ -19,6 +19,7 @@ ; will typically require only insertion of a line. [common] subdirectories = + AAP AMDGPU ARM AArch64 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_i3_short}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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_i3_short}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %0 = sub i16 %x, ptrtoint (i16* @i16_glob to i16) + ret i16 %0 ;CHECK: jmp {{.*JMP}} +} Index: test/CodeGen/AAP/load-offset.ll =================================================================== --- /dev/null +++ test/CodeGen/AAP/load-offset.ll @@ -0,0 +1,406 @@ +; 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(_short)?}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 2] {{.*LDB(_short)?}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 3] {{.*LDB(_short)?}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 4] {{.*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 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 26] {{.*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 ${{r[0-9]+}}, i8_array {{.*MOVI_i16}} +;CHECK-DAG: addi $[[REG2:r[0-9]+]], ${{r[0-9]+}}, 768 {{.*ADDI_i10}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG2]], 0] {{.*LDB(_short)?}} + %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 ${{r[0-9]+}}, i8_array {{.*MOVI_i16}} +;CHECK-DAG: movi ${{r[0-9]+}}, 1234 {{.*MOVI_i16}} +;CHECK-NOT: BARRIER +;CHECK-DAG: add $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*ADD_r(_short)?}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB(_short)?}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], -2] {{.*LDB(_short)?}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], -4] {{.*LDB(_short)?}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], -5] {{.*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 {{.*MOVI_i16}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], -26] {{.*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 ${{r[0-9]+}}, i8_array {{.*MOVI_i16}} +;CHECK-DAG: subi $[[REG2:r[0-9]+]], ${{r[0-9]+}}, 755 {{.*SUBI_i10}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG2]], 0] {{.*LDB(_short)?}} + %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 ${{r[0-9]+}}, i8_array {{.*MOVI_i16}} +;CHECK-DAG: movi ${{r[0-9]+}}, 1234 {{.*MOVI_i16}} +;CHECK-NOT: BARRIER +;CHECK-DAG: sub $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*SUB_r(_short)?}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB(_short)?}} + %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(_short)?}} + %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(_short)?}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB(_short)?}} + %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(_short)?}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB(_short)?}} + %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(_short)?}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB(_short)?}} + %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(_short)?}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB(_short)?}} + %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(_short)?}} +;CHECK-DAG: ldb ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDB(_short)?}} + %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(_short)?}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 2] {{.*LDW(_short)?}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 424] {{.*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 ${{r[0-9]+}}, i16_array {{.*MOVI_i16}} +;CHECK-DAG: movi ${{r[0-9]+}}, 2468 {{.*MOVI_i16}} +;CHECK-NOT: BARRIER +;CHECK-DAG: add $[[REG1:r[0-9]+]], ${{r[0-9]+}}, ${{r[0-9]+}} {{.*ADD_r(_short)?}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW(_short)?}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], -4] {{.*LDW(_short)?}} + %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 ${{r[0-9]+}}, i16_array {{.*MOVI_i16}} +;CHECK-DAG: subi $[[REG2:r[0-9]+]], ${{r[0-9]+}}, 634 {{.*SUBI_i10}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG2]], 0] {{.*LDW(_short)?}} + %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(_short)?}} + %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(_short)?}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW(_short)?}} + %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(_short)?}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW(_short)?}} + %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(_short)?}} +;CHECK-DAG: ldw ${{r[0-9]+}}, [$[[REG1]], 0] {{.*LDW(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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_i3_short}} + %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(_short)?}} + %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_i3_short}} + %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(_short)?}} + %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_i3_short}} + %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(_short)?}} + %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,105 @@ +; 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 {{.*MOVI_i16}} +;CHECK-DAG: stb [$[[REG2]], 3], $[[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 {{.*MOVI_i16}} +;CHECK-DAG: stb [$[[REG2]], 4], $[[REG1]] {{.*STB$}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: stb [$[[REG2]], 511], $[[REG1]] {{.*STB$}} + %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 {{.*MOVI_i16}} +;CHECK-DAG: subi $[[REG2:r[0-9]+]], ${{r[0-9]+}}, 513 {{.*SUBI_i10}} +;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(_short)?}} + %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(_short)?}} + 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(_short)?}} + 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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + 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(_short)?}} + 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(_short)?}} + %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(_short)?}} + 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(_short)?}} + 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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + 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(_short)?}} + 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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %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(_short)?}} + %0 = trunc i16 %y to i8 + store i8 %0, i8* %x, align 1 + ret void ;CHECK: jmp {{.*JMP}} +} Index: test/MC/AAP/alu.s =================================================================== --- /dev/null +++ test/MC/AAP/alu.s @@ -0,0 +1,90 @@ +; RUN: llvm-mc -triple=aap -show-encoding %s | FileCheck %s + +; Basic tests to check that we always pick the correct (and shortest) +; alu operations. + + +; ALU operations with registers +add $r0, $r0, $r0 ;CHECK: encoding: [0x00,0x02] +add $r1, $r2, $r7 ;CHECK: encoding: [0x57,0x02] +add $r7, $r7, $r7 ;CHECK: encoding: [0xff,0x03] +add $r8, $r0, $r5 ;CHECK: encoding: [0x05,0x82,0x40,0x00] +add $r8, $r8, $r12 ;CHECK: encoding: [0x04,0x82,0x49,0x00] +add $r2, $r54, $r8 ;CHECK: encoding: [0xb0,0x82,0x31,0x00] +add $r1, $r32, $r12 ;CHECK: encoding: [0x44,0x82,0x21,0x00] + +xor $r0, $r0, $r0 ;CHECK: encoding: [0x00,0x0a] +and $r1, $r2, $r7 ;CHECK: encoding: [0x57,0x06] +or $r7, $r7, $r1 ;CHECK: encoding: [0xf9,0x09] +sub $r9, $r1, $r5 ;CHECK: encoding: [0x4d,0x84,0x40,0x00] +addc $r9, $r9, $r12 ;CHECK: encoding: [0x4c,0x82,0x49,0x02] +subc $r4, $r55, $r8 ;CHECK: encoding: [0x38,0x85,0x31,0x02] +asr $r4, $r33, $r12 ;CHECK: encoding: [0x0c,0x8d,0x21,0x00] +lsr $r15, $r3, $r8 ;CHECK: encoding: [0xd8,0x91,0x41,0x00] +lsl $r11, $r10, $r12 ;CHECK: encoding: [0xd4,0x8e,0x49,0x00] + + +; Add/Sub with immediates +addi $r6, $r4, 0 ;CHECK: encoding: [0xa0,0x15] +addi $r7, $r2, 1 ;CHECK: encoding: [0xd1,0x15] +subi $r0, $r5, 3 ;CHECK: encoding: [0x2b,0x16] +subi $r8, $r8, 7 ;CHECK: encoding: [0x07,0x96,0x48,0x00] +addi $r7, $r7, 1023 ;CHECK: encoding: [0xff,0x95,0x07,0x1e] + +; Add/Sub with expressions +addi $r0, $r0, (0 + 0) ;CHECK: encoding: [0x00,0x14] +subi $r7, $r7, (1024 - 1023) ;CHECK: encoding: [0xf9,0x17] +addi $r1, $r5, (8 - 1) ;CHECK: encoding: [0x6f,0x14] +subi $r3, $r0, (7 + 1) ;CHECK: encoding: [0xc0,0x96,0x01,0x00] + +; Add/Sub with relocs +addi $r5, $r2, a ;CHECK: encoding: [0b01010AAA,0x95,0x00,0x00] +subi $r7, $r0, b ;CHECK: encoding: [0b11000AAA,0x97,0x00,0x00] + + +; Logical operation with immediates +andi $r0, $r2, 7 ;CHECK: encoding: [0x17,0x86,0x00,0x02] +ori $r1, $r5, 0 ;CHECK: encoding: [0x68,0x88,0x00,0x02] +xori $r6, $r7, 6 ;CHECK: encoding: [0xbe,0x8b,0x00,0x02] +andi $r8, $r0, 123 ;CHECK: encoding: [0x03,0x86,0x47,0x06] +ori $r5, $r8, 12 ;CHECK: encoding: [0x44,0x89,0x09,0x02] +xori $r15, $r54, 15 ;CHECK: encoding: [0xf7,0x8b,0x71,0x02] +andi $r9, $r14, 511 ;CHECK: encoding: [0x77,0x86,0x4f,0x1e] + +; Logical operations with expressions +andi $r0, $r1, (5 - 3) ;CHECK: encoding: [0x0a,0x86,0x00,0x02] +xori $r15, $r12, (0 - 0) ;CHECK: encoding: [0xe0,0x8b,0x48,0x02] +ori $r43, $r19, (15 + 48) ;CHECK: encoding: [0xdf,0x88,0x57,0x03] + +; Logical operations with relocations +andi $r5, $r1, a ;CHECK: encoding: [0b01001AAA,0x87,0x00,0x02] +xori $r11, $r5, a+b ;CHECK: encoding: [0b11101AAA,0x8a,0x40,0x02] +ori $r0, $r0, c-a ;CHECK: encoding: [0b00000AAA,0x88,0x00,0x02] + + +; Shift operations with immediates +lsli $r0, $r0, 1 ;CHECK: encoding: [0x00,0x1a] +lsri $r4, $r0, 2 ;CHECK: encoding: [0x01,0x1d] +asri $r7, $r1, 8 ;CHECK: encoding: [0xcf,0x19] +asri $r7, $r3, 5 ;CHECK: encoding: [0xdc,0x19] + +lsli $r0, $r8, 1 ;CHECK: encoding: [0x00,0x9a,0x08,0x00] +lsli $r8, $r5, 3 ;CHECK: encoding: [0x2a,0x9a,0x40,0x00] +lsri $r31, $r15, 4 ;CHECK: encoding: [0xfb,0x9d,0xc8,0x00] +asri $r7, $r35, 1 ;CHECK: encoding: [0xd8,0x99,0x20,0x00] + +lsli $r2, $r4, 9 ;CHECK: encoding: [0xa0,0x9a,0x01,0x00] +lsri $r8, $r0, 12 ;CHECK: encoding: [0x03,0x9c,0x41,0x00] +asri $r7, $r1, 34 ;CHECK: encoding: [0xc9,0x99,0x04,0x00] +asri $r7, $r3, 63 ;CHECK: encoding: [0xde,0x99,0x07,0x00] + +; Shift operations with expressions +lsri $r4, $r2, (3 + 2) ;CHECK: encoding: [0x14,0x1d] +asri $r1, $r1, (1 + 0) ;CHECK: encoding: [0x48,0x18] +lsli $r2, $r7, (128 - 65) ;CHECK: encoding: [0xbe,0x9a,0x07,0x00] +lsri $r8, $r0, (1 + 2) ;CHECK: encoding: [0x02,0x9c,0x40,0x00] + +; Shift operations with relocations +lsli $r0, $r5, a ;CHECK: encoding: [0b00101AAA,0x9a,0x00,0x00] +lsri $r0, $r5, b ;CHECK: encoding: [0b00101AAA,0x9c,0x00,0x00] +asri $r0, $r5, c ;CHECK: encoding: [0b00101AAA,0x98,0x00,0x00] Index: test/MC/AAP/branch.s =================================================================== --- /dev/null +++ test/MC/AAP/branch.s @@ -0,0 +1,22 @@ +; RUN: llvm-mc -triple=aap -show-encoding %s | FileCheck %s + +; Basic tests to check that we always pick the correct (and shorest) +; branch instructions +; Short branch instructions are never assembled + +beq 511, $r0, $r1 ;CHECK: encoding: [0xc1,0xc5,0xc0,0x0f] +bne -512, $r7, $r0 ;CHECK: encoding: [0x38,0xc6,0x00,0x10] +blts 15, $r13, $r61 ;CHECK: encoding: [0xed,0xc9,0x4f,0x00] +bles 32, $r9, $r8 ;CHECK: encoding: [0x08,0xca,0x09,0x01] +bltu 186, $r11, $r12 ;CHECK: encoding: [0x9c,0xcc,0xc9,0x05] +bleu -1, $r17, $r19 ;CHECK: encoding: [0xcb,0xcf,0xd2,0x1f] + +bra 123 ;CHECK: encoding: [0x7b,0xc0,0x00,0x00] +bra -6810 ;CHECK: encoding: [0x66,0xc1,0xf2,0x1f] +bra -131072 ;CHECK: encoding: [0x00,0xc0,0x00,0x1f] +bra 131071 ;CHECK: encoding: [0xff,0xc1,0xff,0x00] + +bal 481, $r14 ;CHECK: encoding: [0x0e,0xc3,0x39,0x00] +bal -1892, $r58 ;CHECK: encoding: [0xe2,0xc2,0x17,0x1f] +bal 32767, $r0 ;CHECK: encoding: [0xf8,0xc3,0xf8,0x0f] +bal -32768, $r15 ;CHECK: encoding: [0x07,0xc2,0x01,0x10] Index: test/MC/AAP/load.s =================================================================== --- /dev/null +++ test/MC/AAP/load.s @@ -0,0 +1,102 @@ +; RUN: llvm-mc -triple=aap -show-encoding %s | FileCheck %s + +; Basic tests to check that we always pick the correct (and shortest) +; load instructions. + +; Byte loads with immediates +ldb $r7, [$r1, 0] ;CHECK: encoding: [0xc8,0x21] +ldb $r0, [$r0, 2] ;CHECK: encoding: [0x02,0x20] +ldb $r7, [$r7, 3] ;CHECK: encoding: [0xfb,0x21] +ldb $r4, [$r1, -1] ;CHECK: encoding: [0x0f,0x21] +ldb $r6, [$r0, -4] ;CHECK: encoding: [0x84,0x21] +ldb $r5, [$r8, 0] ;CHECK: encoding: [0x40,0xa1,0x08,0x00] +ldb $r16, [$r1, 2] ;CHECK: encoding: [0x0a,0xa0,0x80,0x00] +ldb $r1, [$r2, 4] ;CHECK: encoding: [0x54,0xa0,0x00,0x00] +ldb $r6, [$r3, -5] ;CHECK: encoding: [0x9b,0xa1,0x07,0x1e] +ldb $r43, [$r56, 12] ;CHECK: encoding: [0xc4,0xa0,0x79,0x01] +ldb $r11, [$r11, 511] ;CHECK: encoding: [0xdf,0xa0,0x4f,0x0e] +ldb $r53, [$r63, -512] ;CHECK: encoding: [0x78,0xa1,0xb8,0x11] + +; Byte loads with expressions +ldb $r0, [$r4, (5 - 3)] ;CHECK: encoding: [0x22,0x20] +ldb $r5, [$r7, (81726 - 81727)] ;CHECK: encoding: [0x7f,0x21] +ldb $r2, [$r6, (-5 + 1)] ;CHECK: encoding: [0xb4,0x20] +ldb $r15, [$r34, (0 + 0)] ;CHECK: encoding: [0xd0,0xa1,0x60,0x00] +ldb $r45, [$r0, (5 - 2)] ;CHECK: encoding: [0x43,0xa1,0x40,0x01] +ldb $r0, [$r61, (11 - 9)] ;CHECK: encoding: [0x2a,0xa0,0x38,0x00] +ldb $r5, [$r1, (256 + 255)] ;CHECK: encoding: [0x4f,0xa1,0x07,0x0e] +ldb $r43, [$r17, (-256 - 256)] ;CHECK: encoding: [0xc8,0xa0,0x50,0x11] + +; Byte loads with relocations +ldb $r0, [$r5, a] ;CHECK: encoding: [0b00101AAA,0xa0,0x00,0x00] +ldb $r1, [$r3, b] ;CHECK: encoding: [0b01011AAA,0xa0,0x00,0x00] +ldb $r17, [$r39, b] ;CHECK: encoding: [0b01111AAA,0xa0,0xa0,0x00] +ldb $r15, [$r11, (a - b)] ;CHECK: encoding: [0b11011AAA,0xa1,0x48,0x00] + +; Postinc/Predec bytes loads with immediate +ldb $r5, [$r4+, 0] ;CHECK: encoding: [0x60,0x23] +ldb $r0, [$r2+, 2] ;CHECK: encoding: [0x12,0x22] +ldb $r1, [-$r6, 2] ;CHECK: encoding: [0x72,0x24] +ldb $r7, [-$r2, -2] ;CHECK: encoding: [0xd6,0x25] +ldb $r1, [-$r7, -4] ;CHECK: encoding: [0x7c,0x24] +ldb $r5, [$r8+, 3] ;CHECK: encoding: [0x43,0xa3,0x08,0x00] +ldb $r11, [$r1+, 1] ;CHECK: encoding: [0xc9,0xa2,0x40,0x00] +ldb $r3, [-$r5, 5] ;CHECK: encoding: [0xed,0xa4,0x00,0x00] +ldb $r2, [-$r3, -5] ;CHECK: encoding: [0x9b,0xa4,0x07,0x1e] +ldb $r41, [$r56+, 12] ;CHECK: encoding: [0x44,0xa2,0x79,0x01] +ldb $r34, [$r11+, 511] ;CHECK: encoding: [0x9f,0xa2,0x0f,0x0f] +ldb $r60, [$r63+, -512] ;CHECK: encoding: [0x38,0xa3,0xf8,0x11] + +; Postinc/Predec byte loads with expressions +ldb $r1, [$r7+, (5 - 3)] ;CHECK: encoding: [0x7a,0x22] +ldb $r5, [-$r1, (81726 - 81727)] ;CHECK: encoding: [0x4f,0x25] +ldb $r7, [-$r6, (-5 + 1)] ;CHECK: encoding: [0xf4,0x25] +ldb $r29, [$r34+, (0 + 0)] ;CHECK: encoding: [0x50,0xa3,0xe0,0x00] +ldb $r40, [-$r1, (5 - 2)] ;CHECK: encoding: [0x0b,0xa4,0x40,0x01] +ldb $r0, [$r61+, (11 - 9)] ;CHECK: encoding: [0x2a,0xa2,0x38,0x00] +ldb $r5, [$r1+, (256 + 255)] ;CHECK: encoding: [0x4f,0xa3,0x07,0x0e] +ldb $r43, [$r17+, (-256 - 256)] ;CHECK: encoding: [0xc8,0xa2,0x50,0x11] + +; Postinc/Predec byte loads with relocations +ldb $r0, [$r5+, a] ;CHECK: encoding: [0b00101AAA,0xa2,0x00,0x00] +ldb $r1, [-$r3, b] ;CHECK: encoding: [0b01011AAA,0xa4,0x00,0x00] +ldb $r17, [$r39+, b] ;CHECK: encoding: [0b01111AAA,0xa2,0xa0,0x00] +ldb $r15, [-$r11, (a - b)] ;CHECK: encoding: [0b11011AAA,0xa5,0x48,0x00] + + +; Word loads with immediates +ldw $r7, [$r1, 0] ;CHECK: encoding: [0xc8,0x29] +ldw $r4, [$r1, -1] ;CHECK: encoding: [0x0f,0x29] +ldw $r6, [$r0, -4] ;CHECK: encoding: [0x84,0x29] +ldw $r5, [$r8, 0] ;CHECK: encoding: [0x40,0xa9,0x08,0x00] +ldw $r6, [$r3, -5] ;CHECK: encoding: [0x9b,0xa9,0x07,0x1e] +ldw $r53, [$r63, -512] ;CHECK: encoding: [0x78,0xa9,0xb8,0x11] + +; Word loads with expressions +ldw $r0, [$r4, (5 - 3)] ;CHECK: encoding: [0x22,0x28] +ldw $r5, [$r7, (81726 - 81727)] ;CHECK: encoding: [0x7f,0x29] +ldw $r15, [$r34, (0 + 0)] ;CHECK: encoding: [0xd0,0xa9,0x60,0x00] +ldw $r43, [$r17, (-256 - 256)] ;CHECK: encoding: [0xc8,0xa8,0x50,0x11] + +; Word loads with relocations +ldw $r17, [$r39, b] ;CHECK: encoding: [0b01111AAA,0xa8,0xa0,0x00] +ldw $r15, [$r11, (a - b)] ;CHECK: encoding: [0b11011AAA,0xa9,0x48,0x00] + +; Postinc/Predec word loads with immediates +ldw $r0, [$r2+, 2] ;CHECK: encoding: [0x12,0x2a] +ldw $r7, [-$r2, -2] ;CHECK: encoding: [0xd6,0x2d] +ldw $r1, [-$r7, -4] ;CHECK: encoding: [0x7c,0x2c] +ldw $r11, [$r1+, 1] ;CHECK: encoding: [0xc9,0xaa,0x40,0x00] +ldw $r2, [-$r3, -5] ;CHECK: encoding: [0x9b,0xac,0x07,0x1e] +ldw $r60, [$r63+, -512] ;CHECK: encoding: [0x38,0xab,0xf8,0x11] + +; Postinc/Predec word loads with expressions +ldw $r1, [$r7+, (5 - 3)] ;CHECK: encoding: [0x7a,0x2a] +ldw $r7, [-$r6, (-5 + 1)] ;CHECK: encoding: [0xf4,0x2d] +ldw $r29, [$r34+, (0 + 0)] ;CHECK: encoding: [0x50,0xab,0xe0,0x00] +ldw $r40, [-$r1, (5 - 2)] ;CHECK: encoding: [0x0b,0xac,0x40,0x01] +ldw $r43, [$r17+, (-256 - 256)] ;CHECK: encoding: [0xc8,0xaa,0x50,0x11] + +; Postinc/Predec word loads with relocations +ldw $r17, [$r39+, b] ;CHECK: encoding: [0b01111AAA,0xaa,0xa0,0x00] +ldw $r15, [-$r11, (a - b)] ;CHECK: encoding: [0b11011AAA,0xad,0x48,0x00] Index: test/MC/AAP/move.s =================================================================== --- /dev/null +++ test/MC/AAP/move.s @@ -0,0 +1,38 @@ +; RUN: llvm-mc -triple=aap -show-encoding %s | FileCheck %s + +; Basic tests to check that we always pick the correct (and shortest) +; move instructions. + +; Moves with registers +mov $r0, $r0 ;CHECK: encoding: [0x00,0x12] +mov $r7, $r7 ;CHECK: encoding: [0xf8,0x13] +mov $r8, $r8 ;CHECK: encoding: [0x00,0x92,0x48,0x00] +mov $r15, $r1 ;CHECK: encoding: [0xc8,0x93,0x40,0x00] +mov $r3, $r11 ;CHECK: encoding: [0xd8,0x92,0x08,0x00] + +; Moves with immediates +movi $r0, 0 ;CHECK: encoding: [0x00,0x1e] +movi $r5, -0 ;CHECK: encoding: [0x40,0x1f] +movi $r7, +0 ;CHECK: encoding: [0xc0,0x1f] +movi $r2, 13 ;CHECK: encoding: [0x8d,0x1e] +movi $r3, 63 ;CHECK: encoding: [0xff,0x1e] +movi $r3, 0x12 ;CHECK: encoding: [0xd2,0x1e] +movi $r4, 64 ;CHECK: encoding: [0x00,0x9f,0x01,0x00] +movi $r10, 0 ;CHECK: encoding: [0x80,0x9e,0x40,0x00] +movi $r8, 123 ;CHECK: encoding: [0x3b,0x9e,0x41,0x00] +movi $r9, 65535 ;CHECK: encoding: [0x7f,0x9e,0x7f,0x1e] +movi $r1, -1 ;CHECK: encoding: [0x7f,0x9e,0x3f,0x1e] +movi $r9, -32768 ;CHECK: encoding: [0x40,0x9e,0x40,0x10] +movi $r16, 0xdead ;CHECK: encoding: [0x2d,0x9e,0xba,0x1a] +movi $r63, -0x1 ;CHECK: encoding: [0xff,0x9f,0xff,0x1f] +movi $r63, -0x7fff ;CHECK: encoding: [0xc1,0x9f,0xc0,0x11] + +; Moves with expressions +movi $r2, (5 + 5) ;CHECK: [0x8a,0x1e] +movi $r4, (65 - 10) ;CHECK: [0x37,0x1f] +movi $r12, (0xdead - 0xbeef) ;CHECK: [0x3e,0x9f,0x7e,0x02] + +; Moves with relocations. These should always assemble to long instructions +movi $r0, a ;CHECK: encoding: [0b00AAAAAA,0x9e,0x00,0x00] +movi $r8, b ;CHECK: encoding: [0b00AAAAAA,0x9e,0x40,0x00] +movi $r16, (a + b) ;CHECK: encoding: [0b00AAAAAA,0x9e,0x80,0x00] Index: test/MC/AAP/noop.s =================================================================== --- /dev/null +++ test/MC/AAP/noop.s @@ -0,0 +1,10 @@ +; RUN: llvm-mc -triple=aap -show-encoding %s | FileCheck %s + +; Basic tests to check that we always pick the correct (and shortest) +; noop instruction. + +nop $r0, 5 ;CHECK: encoding: [0x05,0x00] +nop $r7, 63 ;CHECK: encoding: [0xff,0x01] +nop $r8, 53 ;CHECK: encoding: [0x35,0x80,0x40,0x00] +nop $r4, 64 ;CHECK: encoding: [0x00,0x81,0x01,0x00] +nop $r63, a ;CHECK: encoding: [0b11AAAAAA,0x81,0xc0,0x01] Index: test/MC/AAP/store.s =================================================================== --- /dev/null +++ test/MC/AAP/store.s @@ -0,0 +1,98 @@ +; RUN: llvm-mc -triple=aap -show-encoding %s | FileCheck %s + +; Basic tests to check that we always pick the correct (and shortest) +; store instructions. + +; Byte stores with immediates +stb [$r0, 0], $r0 ;CHECK: encoding: [0x00,0x30] +stb [$r1, 2], $r1 ;CHECK: encoding: [0x4a,0x30] +stb [$r7, 3], $r3 ;CHECK: encoding: [0xdb,0x31] +stb [$r1, -1], $r7 ;CHECK: encoding: [0x7f,0x30] +stb [$r5, -4], $r5 ;CHECK: encoding: [0x6c,0x31] +stb [$r8, 0], $r0 ;CHECK: encoding: [0x00,0xb0,0x40,0x00] +stb [$r1, 4], $r0 ;CHECK: encoding: [0x44,0xb0,0x00,0x00] +stb [$r7, 3], $r8 ;CHECK: encoding: [0xc3,0xb1,0x08,0x00] +stb [$r15, -1], $r7 ;CHECK: encoding: [0xff,0xb1,0x47,0x1e] +stb [$r6, -5], $r2 ;CHECK: encoding: [0x93,0xb1,0x07,0x1e] +stb [$r63, 2], $r7 ;CHECK: encoding: [0xfa,0xb1,0xc0,0x01] +stb [$r5, 1], $r26 ;CHECK: encoding: [0x51,0xb1,0x18,0x00] +stb [$r63, 511], $r19 ;CHECK: encoding: [0xdf,0xb1,0xd7,0x0f] +stb [$r52, -512], $r14 ;CHECK: encoding: [0x30,0xb1,0x88,0x11] + +; Byte stores with expressions +stb [$r1, (-(3 - 2))], $r2 ;CHECK: encoding: [0x57,0x30] +stb [$r4, (1234 - 1233)], $r7 ;CHECK: encoding: [0x39,0x31] +stb [$r6, (-2 + 1)], $r2 ;CHECK: encoding: [0x97,0x31] +stb [$r1, (1024 - 513)], $r0 ;CHECK: encoding: [0x47,0xb0,0x07,0x0e] +stb [$r40, (-256 + 123)], $r16 ;CHECK: encoding: [0x03,0xb0,0x57,0x1b] +stb [$r18, (0xdead - 0xdeaf)], $r8 ;CHECK: encoding: [0x86,0xb0,0x8f,0x1e] + +; Byte stores with relocations +stb [$r0, a], $r1 ;CHECK: encoding: [0b00001AAA,0xb0,0x00,0x00] +stb [$r7, b], $r2 ;CHECK: encoding: [0b11010AAA,0xb1,0x00,0x00] +stb [$r1, (c - a)], $r50 ;CHECK: encoding: [0b01010AAA,0xb0,0x30,0x00] + +; Postinc/Predec byte stores with immediates +stb [$r5+, 1], $r0 ;CHECK: encoding: [0x41,0x33] +stb [$r6+, 3], $r2 ;CHECK: encoding: [0x93,0x33] +stb [-$r7, 2], $r7 ;CHECK: encoding: [0xfa,0x35] +stb [-$r1, -1], $r7 ;CHECK: encoding: [0x7f,0x34] +stb [$r2+, -4], $r2 ;CHECK: encoding: [0x94,0x32] +stb [$r9+, 1], $r8 ;CHECK: encoding: [0x41,0xb2,0x48,0x00] +stb [$r1+, 4], $r0 ;CHECK: encoding: [0x44,0xb2,0x00,0x00] +stb [-$r7, -5], $r8 ;CHECK: encoding: [0xc3,0xb5,0x0f,0x1e] +stb [-$r12, -1], $r7 ;CHECK: encoding: [0x3f,0xb5,0x47,0x1e] +stb [-$r61, -5], $r2 ;CHECK: encoding: [0x53,0xb5,0xc7,0x1f] +stb [$r25+, 2], $r7 ;CHECK: encoding: [0x7a,0xb2,0xc0,0x00] +stb [$r1+, 1], $r29 ;CHECK: encoding: [0x69,0xb2,0x18,0x00] +stb [-$r27, 511], $r19 ;CHECK: encoding: [0xdf,0xb4,0xd7,0x0e] +stb [$r52+, -512], $r44 ;CHECK: encoding: [0x20,0xb3,0xa8,0x11] + +; Postinc/Predec byte stores with expressions +stb [$r0+, (-(-5 + 4))], $r0 ;CHECK: encoding: [0x01,0x32] +stb [-$r2, (91 - 95)], $r2 ;CHECK: encoding: [0x94,0x34] +stb [$r6+, (2 - 1)], $r2 ;CHECK: encoding: [0x91,0x33] +stb [-$r1, (1024 - 513)], $r8 ;CHECK: encoding: [0x47,0xb4,0x0f,0x0e] +stb [$r40+, (-256 + 256)], $r16 ;CHECK: encoding: [0x00,0xb2,0x50,0x01] +stb [-$r18, (0xdead - 0xdead)], $r8 ;CHECK: encoding: [0x80,0xb4,0x88,0x00] + +; Postinc/Predec byte stores with relocations +stb [$r7+, a], $r6 ;CHECK: encoding: [0b11110AAA,0xb3,0x00,0x00] +stb [-$r0, b], $r3 ;CHECK: encoding: [0b00011AAA,0xb4,0x00,0x00] +stb [$r1+, (b + a)], $r8 ;CHECK: encoding: [0b01000AAA,0xb2,0x08,0x00] + + +; Word stores with immediates +stw [$r1, 2], $r1 ;CHECK: encoding: [0x4a,0x38] +stw [$r7, 3], $r3 ;CHECK: encoding: [0xdb,0x39] +stw [$r8, 0], $r0 ;CHECK: encoding: [0x00,0xb8,0x40,0x00] +stw [$r6, -5], $r2 ;CHECK: encoding: [0x93,0xb9,0x07,0x1e] +stw [$r5, 1], $r26 ;CHECK: encoding: [0x51,0xb9,0x18,0x00] + +; Word stores with expressions +stw [$r4, (1234 - 1233)], $r7 ;CHECK: encoding: [0x39,0x39] +stw [$r6, (-2 + 1)], $r2 ;CHECK: encoding: [0x97,0x39] +stw [$r1, (1024 - 513)], $r0 ;CHECK: encoding: [0x47,0xb8,0x07,0x0e] +stw [$r18, (0xdead - 0xdeaf)], $r8 ;CHECK: encoding: [0x86,0xb8,0x8f,0x1e] + +; Word stores with relocations +stw [$r7, b], $r2 ;CHECK: encoding: [0b11010AAA,0xb9,0x00,0x00] +stw [$r1, (c - a)], $r50 ;CHECK: encoding: [0b01010AAA,0xb8,0x30,0x00] + +; Postinc/Predec word stores with immediates +stw [-$r7, 2], $r7 ;CHECK: encoding: [0xfa,0x3d] +stw [$r2+, -4], $r2 ;CHECK: encoding: [0x94,0x3a] +stw [$r9+, 1], $r8 ;CHECK: encoding: [0x41,0xba,0x48,0x00] +stw [-$r7, -5], $r8 ;CHECK: encoding: [0xc3,0xbd,0x0f,0x1e] +stw [-$r61, -5], $r2 ;CHECK: encoding: [0x53,0xbd,0xc7,0x1f] +stw [$r25+, 2], $r7 ;CHECK: encoding: [0x7a,0xba,0xc0,0x00] + +; Postinc/Predec word stores with expressions +stw [-$r2, (91 - 95)], $r2 ;CHECK: encoding: [0x94,0x3c] +stw [$r6+, (2 - 1)], $r2 ;CHECK: encoding: [0x91,0x3b] +stw [$r40+, (-256 + 256)], $r16 ;CHECK: encoding: [0x00,0xba,0x50,0x01] +stw [-$r18, (0xdead - 0xdead)], $r8 ;CHECK: encoding: [0x80,0xbc,0x88,0x00] + +; Postinc/Predec word stores with relocations +stw [$r7+, a], $r6 ;CHECK: encoding: [0b11110AAA,0xbb,0x00,0x00] +stw [-$r0, b], $r3 ;CHECK: encoding: [0b00011AAA,0xbc,0x00,0x00] Index: tools/aap-run/AAPSimTest.cpp =================================================================== --- /dev/null +++ tools/aap-run/AAPSimTest.cpp @@ -0,0 +1,136 @@ +//===-- AAPSimTest.cpp - AAP Simulator Test --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Test program for using AAP Simulation Library +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "AAPSimulator.h" +#include "AAPSimState.h" + +using namespace llvm; +using namespace object; +using namespace AAPSim; + +static cl::opt +InputFilename(cl::Positional, cl::Required, cl::desc("")); + +static std::string ToolName; + +static void report_error(StringRef File, std::error_code EC) { + assert(EC); + errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n"; + exit(1); +} + +static void LoadObject(AAPSimulator &Sim, ObjectFile *o) { + unsigned i = 0; + for (const SectionRef &Section : o->sections()) { + StringRef Name; + Section.getName(Name); + uint64_t Address = Section.getAddress(); + uint64_t Size = Section.getSize(); + bool Text = Section.isText(); + bool Data = Section.isData(); + bool BSS = Section.isBSS(); + bool TextFlag = Address & 0x8000000; + StringRef BytesStr; + Section.getContents(BytesStr); + std::string Type = (std::string(Text ? "TEXT " : "") + + (Data ? "DATA " : "") + (BSS ? "BSS" : "")); + // FIXME: We should really load based on LOAD segment flag + if (Text || Data) { + outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n", i, + Name.str().c_str(), Size, Address, Type.c_str()); + if (TextFlag) { + Address = Address & 0xffffff; + outs() << format("Writing %s to %06" PRIx64 "\n", Name.str().c_str(), Address); + Sim.WriteCodeSection(BytesStr, Address); + } else { + Address = Address & 0xffff; + outs() << format("Writing %s to %04" PRIx64 "\n", Name.str().c_str(), Address); + Sim.WriteDataSection(BytesStr, Address); + } + } + ++i; + } + // Set PC + Sim.setPC(0x0); +} + +// Load an object +static void LoadBinary(AAPSimulator &Sim, std::string filename) { + // Attempt to open the binary. + ErrorOr> BinaryOrErr = createBinary(filename); + if (std::error_code EC = BinaryOrErr.getError()) + report_error(filename, EC); + Binary &Binary = *BinaryOrErr.get().getBinary(); + if (ObjectFile *o = dyn_cast(&Binary)) + LoadObject(Sim, o); + else + report_error(filename, object_error::invalid_file_type); +} + +int main(int argc, char **argv) { + // Init LLVM, call llvm_shutdown() on exit, parse args, etc. + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; + + // Initialize targets and assembly printers/parsers. + // (FIXME: Move this into AAPSimulator?) + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllDisassemblers(); + + cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); + cl::ParseCommandLineOptions(argc, argv, "AAP Simulator Test\n"); + + // Set up Simulator + AAPSimulator Sim; + + ToolName = argv[0]; + + // Load Binary + LoadBinary(Sim, InputFilename); + SimStatus status = SimStatus::SIM_OK; + while (status == SimStatus::SIM_OK) { + status = Sim.step(); + } + // Deal with the final simulator status + switch (status) { + default: break; + case SimStatus::SIM_INVALID_INSN: + outs() << " *** Attempted to decode invalid instruction ***\n"; + break; + case SimStatus::SIM_BREAKPOINT: + outs() << " *** Breakpoint hit ***\n"; + break; + case SimStatus::SIM_TRAP: + outs() << " *** Simulator trap ***\n"; + break; + case SimStatus::SIM_EXCEPT_MEM: + outs() << " *** Invalid memory trap ***\n"; + return 1; + case SimStatus::SIM_EXCEPT_REG: + outs() << " *** Invalid register trap ***\n"; + return 1; + case SimStatus::SIM_QUIT: + outs() << " *** EXIT CODE " << Sim.getState().getExitCode() << " ***\n"; + return Sim.getState().getExitCode(); + } + + return 0; +} \ No newline at end of file