| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| set(LLVM_TARGET_DEFINITIONS Lanai.td) | ||
|
|
||
| tablegen(LLVM LanaiGenAsmMatcher.inc -gen-asm-matcher) | ||
| tablegen(LLVM LanaiGenAsmWriter.inc -gen-asm-writer) | ||
| tablegen(LLVM LanaiGenCallingConv.inc -gen-callingconv) | ||
| tablegen(LLVM LanaiGenDAGISel.inc -gen-dag-isel) | ||
| tablegen(LLVM LanaiGenDisassemblerTables.inc -gen-disassembler) | ||
| tablegen(LLVM LanaiGenInstrInfo.inc -gen-instr-info) | ||
| tablegen(LLVM LanaiGenMCCodeEmitter.inc -gen-emitter) | ||
| tablegen(LLVM LanaiGenRegisterInfo.inc -gen-register-info) | ||
| tablegen(LLVM LanaiGenSubtargetInfo.inc -gen-subtarget) | ||
| add_public_tablegen_target(LanaiCommonTableGen) | ||
|
|
||
| add_llvm_target(LanaiCodeGen | ||
| LanaiAsmPrinter.cpp | ||
| LanaiDelaySlotFiller.cpp | ||
| LanaiFrameLowering.cpp | ||
| LanaiInstrInfo.cpp | ||
| LanaiISelDAGToDAG.cpp | ||
| LanaiISelLowering.cpp | ||
| LanaiMachineFunctionInfo.cpp | ||
| LanaiMCInstLower.cpp | ||
| LanaiMemAluCombiner.cpp | ||
| LanaiRegisterInfo.cpp | ||
| LanaiSelectionDAGInfo.cpp | ||
| LanaiSetflagAluCombiner.cpp | ||
| LanaiSubtarget.cpp | ||
| LanaiTargetMachine.cpp | ||
| LanaiTargetObjectFile.cpp | ||
| ) | ||
|
|
||
| add_subdirectory(AsmParser) | ||
| add_subdirectory(TargetInfo) | ||
| add_subdirectory(MCTargetDesc) | ||
| add_subdirectory(InstPrinter) | ||
| add_subdirectory(Disassembler) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| add_llvm_library(LLVMLanaiDisassembler | ||
| LanaiDisassembler.cpp | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| ;===-- ./lib/Target/Lanai/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 = LanaiDisassembler | ||
| parent = Lanai | ||
| required_libraries = LanaiMCTargetDesc LanaiInfo MC MCDisassembler Support | ||
| add_to_library_groups = Lanai |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,228 @@ | ||
| //===- LanaiDisassembler.cpp - Disassembler for Lanai -----------*- 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 Lanai Disassembler. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "LanaiDisassembler.h" | ||
|
|
||
| #include "Lanai.h" | ||
| #include "LanaiSubtarget.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" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| typedef MCDisassembler::DecodeStatus DecodeStatus; | ||
|
|
||
| namespace llvm { | ||
| extern Target TheLanaiTarget; | ||
| } | ||
|
|
||
| static MCDisassembler *createLanaiDisassembler(const Target &T, | ||
| const MCSubtargetInfo &STI, | ||
| MCContext &Ctx) { | ||
| return new LanaiDisassembler(STI, Ctx); | ||
| } | ||
|
|
||
| extern "C" void LLVMInitializeLanaiDisassembler() { | ||
| // Register the disassembler | ||
| TargetRegistry::RegisterMCDisassembler(TheLanaiTarget, | ||
| createLanaiDisassembler); | ||
| } | ||
|
|
||
| LanaiDisassembler::LanaiDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) | ||
| : MCDisassembler(STI, Ctx) {} | ||
|
|
||
| // Forward declare because the autogenerated code will reference this. | ||
| // Definition is further down. | ||
| DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo, | ||
| uint64_t Address, const void *Decoder); | ||
|
|
||
| static DecodeStatus decodeRiMemoryValue(MCInst &Inst, unsigned Insn, | ||
| uint64_t Address, const void *Decoder); | ||
|
|
||
| static DecodeStatus decodeRrMemoryValue(MCInst &Inst, unsigned Insn, | ||
| uint64_t Address, const void *Decoder); | ||
|
|
||
| static DecodeStatus decodeSplsValue(MCInst &Inst, unsigned Insn, | ||
| uint64_t Address, const void *Decoder); | ||
|
|
||
| static DecodeStatus decodeBranch(MCInst &Inst, unsigned Insn, uint64_t Address, | ||
| const void *Decoder); | ||
|
|
||
| static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn, | ||
| uint64_t Address, const void *Decoder); | ||
|
|
||
| #include "LanaiGenDisassemblerTables.inc" | ||
|
|
||
| static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address, | ||
| uint64_t &Size, uint32_t &Insn) { | ||
| // We want to read exactly 4 bytes of data. | ||
| if (Bytes.size() < 4) { | ||
| Size = 0; | ||
| return MCDisassembler::Fail; | ||
| } | ||
|
|
||
| // Encoded as big-endian 32-bit word in the stream. | ||
| Insn = | ||
| (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 8) | (Bytes[3] << 0); | ||
|
|
||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static void PostOperandDecodeAdjust(MCInst &Instr, uint32_t Insn) { | ||
| unsigned AluOp = LPAC::ADD; | ||
| // Fix up for pre and post operations. | ||
| int PqShift = -1; | ||
| if (isRMOpcode(Instr.getOpcode())) | ||
| PqShift = 16; | ||
| else if (isSPLSOpcode(Instr.getOpcode())) | ||
| PqShift = 10; | ||
| else if (isRRMOpcode(Instr.getOpcode())) { | ||
| PqShift = 16; | ||
| // Determine RRM ALU op. | ||
| AluOp = (Insn >> 8) & 0x7; | ||
| if (AluOp == 7) | ||
| // Handle JJJJJ | ||
| // 0b10000 or 0b11000 | ||
| AluOp |= 0x20 | (((Insn >> 3) & 0xf) << 1); | ||
| } | ||
|
|
||
| if (PqShift != -1) { | ||
| unsigned PQ = (Insn >> PqShift) & 0x3; | ||
| switch (PQ) { | ||
| case 0x0: | ||
| if (Instr.getOperand(2).isReg()) { | ||
| Instr.getOperand(2).setReg(Lanai::R0); | ||
| } | ||
| if (Instr.getOperand(2).isImm()) | ||
| Instr.getOperand(2).setImm(0); | ||
| break; | ||
| case 0x1: | ||
| AluOp = LPAC::makePostOp(AluOp); | ||
| break; | ||
| case 0x2: | ||
| break; | ||
| case 0x3: | ||
| AluOp = LPAC::makePreOp(AluOp); | ||
| break; | ||
| } | ||
| Instr.addOperand(MCOperand::createImm(AluOp)); | ||
| } | ||
| } | ||
|
|
||
| DecodeStatus LanaiDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, | ||
| ArrayRef<uint8_t> Bytes, | ||
| uint64_t Address, | ||
| raw_ostream &VStream, | ||
| raw_ostream &CStream) const { | ||
| uint32_t Insn; | ||
|
|
||
| DecodeStatus Result = readInstruction32(Bytes, Address, Size, Insn); | ||
|
|
||
| if (Result == MCDisassembler::Fail) | ||
| return MCDisassembler::Fail; | ||
|
|
||
| // Call auto-generated decoder function | ||
| Result = | ||
| decodeInstruction(DecoderTableLanai32, Instr, Insn, Address, this, STI); | ||
|
|
||
| if (Result != MCDisassembler::Fail) { | ||
| PostOperandDecodeAdjust(Instr, Insn); | ||
| Size = 4; | ||
| return Result; | ||
| } | ||
|
|
||
| return MCDisassembler::Fail; | ||
| } | ||
|
|
||
| static const unsigned GPRDecoderTable[] = { | ||
| Lanai::R0, Lanai::R1, Lanai::PC, Lanai::R3, Lanai::SP, Lanai::FP, | ||
| Lanai::R6, Lanai::R7, Lanai::RV, Lanai::R9, Lanai::RR1, Lanai::RR2, | ||
| Lanai::R12, Lanai::R13, Lanai::R14, Lanai::RCA, Lanai::R16, Lanai::R17, | ||
| Lanai::R18, Lanai::R19, Lanai::R20, Lanai::R21, Lanai::R22, Lanai::R23, | ||
| Lanai::R24, Lanai::R25, Lanai::R26, Lanai::R27, Lanai::R28, Lanai::R29, | ||
| Lanai::R30, Lanai::R31}; | ||
|
|
||
| DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo, | ||
| uint64_t Address, const void *Decoder) { | ||
| if (RegNo > 31) | ||
| return MCDisassembler::Fail; | ||
|
|
||
| unsigned Reg = GPRDecoderTable[RegNo]; | ||
| Inst.addOperand(MCOperand::createReg(Reg)); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static DecodeStatus decodeRiMemoryValue(MCInst &Inst, unsigned Insn, | ||
| uint64_t Address, const void *Decoder) { | ||
| // RI memory values encoded using 23 bits: | ||
| // 5 bit register, 16 bit constant | ||
| unsigned Register = (Insn >> 18) & 0x1f; | ||
| Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register])); | ||
| unsigned Offset = (Insn & 0xffff); | ||
| Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset))); | ||
|
|
||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static DecodeStatus decodeRrMemoryValue(MCInst &Inst, unsigned Insn, | ||
| uint64_t Address, const void *Decoder) { | ||
| // RR memory values encoded using 20 bits: | ||
| // 5 bit register, 5 bit register, 2 bit PQ, 3 bit ALU operator, 5 bit JJJJJ | ||
| unsigned Register = (Insn >> 15) & 0x1f; | ||
| Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register])); | ||
| Register = (Insn >> 10) & 0x1f; | ||
| Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register])); | ||
|
|
||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static DecodeStatus decodeSplsValue(MCInst &Inst, unsigned Insn, | ||
| uint64_t Address, const void *Decoder) { | ||
| // RI memory values encoded using 17 bits: | ||
| // 5 bit register, 10 bit constant | ||
| unsigned Register = (Insn >> 12) & 0x1f; | ||
| Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register])); | ||
| unsigned Offset = (Insn & 0x3ff); | ||
| Inst.addOperand(MCOperand::createImm(SignExtend32<10>(Offset))); | ||
|
|
||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static bool tryAddingSymbolicOperand(int64_t Value, bool IsBranch, | ||
| uint64_t Address, uint64_t Offset, | ||
| uint64_t Width, MCInst &MI, | ||
| const void *Decoder) { | ||
| const MCDisassembler *Dis = static_cast<const MCDisassembler *>(Decoder); | ||
| return Dis->tryAddingSymbolicOperand(MI, Value, Address, IsBranch, Offset, | ||
| Width); | ||
| } | ||
|
|
||
| static DecodeStatus decodeBranch(MCInst &MI, unsigned Insn, uint64_t Address, | ||
| const void *Decoder) { | ||
| if (!tryAddingSymbolicOperand(Insn + Address, false, Address, 2, 23, MI, | ||
| Decoder)) | ||
| MI.addOperand(MCOperand::createImm(Insn)); | ||
| return MCDisassembler::Success; | ||
| } | ||
|
|
||
| static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn, | ||
| uint64_t Address, const void *Decoder) { | ||
| unsigned Offset = (Insn & 0xffff); | ||
| Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset))); | ||
|
|
||
| return MCDisassembler::Success; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| //===- LanaiDisassembler.cpp - Disassembler for Lanai -----------*- 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 Lanai Disassembler. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_LANAI_DISASSEMBLER_LANAIDISASSEMBLER_H | ||
| #define LLVM_LIB_TARGET_LANAI_DISASSEMBLER_LANAIDISASSEMBLER_H | ||
|
|
||
| #define DEBUG_TYPE "lanai-disassembler" | ||
|
|
||
| #include "llvm/MC/MCDisassembler/MCDisassembler.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class MCInst; | ||
| class raw_ostream; | ||
|
|
||
| class LanaiDisassembler : public MCDisassembler { | ||
| public: | ||
| LanaiDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx); | ||
|
|
||
| ~LanaiDisassembler() override {} | ||
|
|
||
| // getInstruction - See MCDisassembler. | ||
| MCDisassembler::DecodeStatus | ||
| getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes, | ||
| uint64_t Address, raw_ostream &VStream, | ||
| raw_ostream &CStream) const override; | ||
| }; | ||
|
|
||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_LANAI_DISASSEMBLER_LANAIDISASSEMBLER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| add_llvm_library(LLVMLanaiInstPrinter | ||
| LanaiInstPrinter.cpp | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| ;===-- ./lib/Target/Lanai/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 = LanaiInstPrinter | ||
| parent = Lanai | ||
| required_libraries = LanaiInfo MC Support | ||
| add_to_library_groups = Lanai |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,309 @@ | ||
| //===-- LanaiInstPrinter.cpp - Convert Lanai MCInst to asm 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 Lanai MCInst to a .s file. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "Lanai.h" | ||
| #include "LanaiInstPrinter.h" | ||
| #include "MCTargetDesc/LanaiMCExpr.h" | ||
| #include "llvm/MC/MCAsmInfo.h" | ||
| #include "llvm/MC/MCExpr.h" | ||
| #include "llvm/MC/MCInst.h" | ||
| #include "llvm/MC/MCSymbol.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. | ||
| #define PRINT_ALIAS_INSTR | ||
| #include "LanaiGenAsmWriter.inc" | ||
|
|
||
| void LanaiInstPrinter::printRegName(raw_ostream &Ostream, | ||
| unsigned RegNo) const { | ||
| Ostream << StringRef(getRegisterName(RegNo)).lower(); | ||
| } | ||
|
|
||
| bool LanaiInstPrinter::printInst(const MCInst *MI, raw_ostream &Ostream, | ||
| StringRef Alias, unsigned OpNo0, | ||
| unsigned OpNo1) { | ||
| Ostream << "\t" << Alias << " "; | ||
| printOperand(MI, OpNo0, Ostream); | ||
| Ostream << ", "; | ||
| printOperand(MI, OpNo1, Ostream); | ||
| return true; | ||
| } | ||
|
|
||
| static bool usesGivenOffset(const MCInst *MI, int AddOffset) { | ||
| unsigned AluCode = MI->getOperand(3).getImm(); | ||
| return LPAC::encodeLanaiAluCode(AluCode) == LPAC::ADD && | ||
| (MI->getOperand(2).getImm() == AddOffset || | ||
| MI->getOperand(2).getImm() == -AddOffset); | ||
| } | ||
|
|
||
| static bool isPreIncrementForm(const MCInst *MI, int AddOffset) { | ||
| unsigned AluCode = MI->getOperand(3).getImm(); | ||
| return LPAC::isPreOp(AluCode) && usesGivenOffset(MI, AddOffset); | ||
| } | ||
|
|
||
| static bool isPostIncrementForm(const MCInst *MI, int AddOffset) { | ||
| unsigned AluCode = MI->getOperand(3).getImm(); | ||
| return LPAC::isPostOp(AluCode) && usesGivenOffset(MI, AddOffset); | ||
| } | ||
|
|
||
| static StringRef decIncOperator(const MCInst *MI) { | ||
| if (MI->getOperand(2).getImm() < 0) | ||
| return "--"; | ||
| return "++"; | ||
| } | ||
|
|
||
| bool LanaiInstPrinter::printMemoryLoadIncrement(const MCInst *MI, | ||
| raw_ostream &Ostream, | ||
| StringRef Opcode, | ||
| int AddOffset) { | ||
| if (isPreIncrementForm(MI, AddOffset)) { | ||
| Ostream << "\t" << Opcode << "\t[" << decIncOperator(MI) << "%" | ||
| << getRegisterName(MI->getOperand(1).getReg()) << "], %" | ||
| << getRegisterName(MI->getOperand(0).getReg()); | ||
| return true; | ||
| } | ||
| if (isPostIncrementForm(MI, AddOffset)) { | ||
| Ostream << "\t" << Opcode << "\t[%" | ||
| << getRegisterName(MI->getOperand(1).getReg()) << decIncOperator(MI) | ||
| << "], %" << getRegisterName(MI->getOperand(0).getReg()); | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| bool LanaiInstPrinter::printMemoryStoreIncrement(const MCInst *MI, | ||
| raw_ostream &Ostream, | ||
| StringRef Opcode, | ||
| int AddOffset) { | ||
| if (isPreIncrementForm(MI, AddOffset)) { | ||
| Ostream << "\t" << Opcode << "\t%" | ||
| << getRegisterName(MI->getOperand(0).getReg()) << ", [" | ||
| << decIncOperator(MI) << "%" | ||
| << getRegisterName(MI->getOperand(1).getReg()) << "]"; | ||
| return true; | ||
| } | ||
| if (isPostIncrementForm(MI, AddOffset)) { | ||
| Ostream << "\t" << Opcode << "\t%" | ||
| << getRegisterName(MI->getOperand(0).getReg()) << ", [%" | ||
| << getRegisterName(MI->getOperand(1).getReg()) << decIncOperator(MI) | ||
| << "]"; | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| bool LanaiInstPrinter::printAlias(const MCInst *MI, raw_ostream &Ostream) { | ||
| switch (MI->getOpcode()) { | ||
| case Lanai::LDW_RI: | ||
| // ld 4[*%rN], %rX => ld [++imm], %rX | ||
| // ld -4[*%rN], %rX => ld [--imm], %rX | ||
| // ld 4[%rN*], %rX => ld [imm++], %rX | ||
| // ld -4[%rN*], %rX => ld [imm--], %rX | ||
| return printMemoryLoadIncrement(MI, Ostream, "ld", 4); | ||
| case Lanai::LDHs_RI: | ||
| return printMemoryLoadIncrement(MI, Ostream, "ld.h", 2); | ||
| case Lanai::LDHz_RI: | ||
| return printMemoryLoadIncrement(MI, Ostream, "uld.h", 2); | ||
| case Lanai::LDBs_RI: | ||
| return printMemoryLoadIncrement(MI, Ostream, "ld.b", 1); | ||
| case Lanai::LDBz_RI: | ||
| return printMemoryLoadIncrement(MI, Ostream, "uld.b", 1); | ||
| case Lanai::SW_RI: | ||
| // st %rX, 4[*%rN] => st %rX, [++imm] | ||
| // st %rX, -4[*%rN] => st %rX, [--imm] | ||
| // st %rX, 4[%rN*] => st %rX, [imm++] | ||
| // st %rX, -4[%rN*] => st %rX, [imm--] | ||
| return printMemoryStoreIncrement(MI, Ostream, "st", 4); | ||
| case Lanai::STH_RI: | ||
| return printMemoryStoreIncrement(MI, Ostream, "st.h", 2); | ||
| case Lanai::STB_RI: | ||
| return printMemoryStoreIncrement(MI, Ostream, "st.b", 1); | ||
| default: | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| void LanaiInstPrinter::printInst(const MCInst *MI, raw_ostream &Ostream, | ||
| StringRef Annotation, | ||
| const MCSubtargetInfo &STI) { | ||
| if (!printAlias(MI, Ostream) && !printAliasInstr(MI, Ostream)) | ||
| printInstruction(MI, Ostream); | ||
| printAnnotation(Ostream, Annotation); | ||
| } | ||
|
|
||
| static void printExpr(const MCAsmInfo &MAI, const MCExpr &Expr, | ||
| raw_ostream &Ostream) { | ||
| const MCExpr *SRE; | ||
|
|
||
| if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(&Expr)) | ||
| SRE = dyn_cast<LanaiMCExpr>(BE->getLHS()); | ||
| else if (isa<LanaiMCExpr>(&Expr)) { | ||
| SRE = dyn_cast<LanaiMCExpr>(&Expr); | ||
| } else { | ||
| SRE = dyn_cast<MCSymbolRefExpr>(&Expr); | ||
| } | ||
| assert(SRE && "Unexpected MCExpr type."); | ||
|
|
||
| SRE->print(Ostream, &MAI); | ||
| } | ||
|
|
||
| void LanaiInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, | ||
| raw_ostream &Ostream, | ||
| const char *Modifier) { | ||
| assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); | ||
| const MCOperand &Op = MI->getOperand(OpNo); | ||
| if (Op.isReg()) | ||
| Ostream << "%" << getRegisterName(Op.getReg()); | ||
| else if (Op.isImm()) | ||
| Ostream << formatHex(Op.getImm()); | ||
| else { | ||
| assert(Op.isExpr() && "Expected an expression"); | ||
| printExpr(MAI, *Op.getExpr(), Ostream); | ||
| } | ||
| } | ||
|
|
||
| void LanaiInstPrinter::printMemImmOperand(const MCInst *MI, unsigned OpNo, | ||
| raw_ostream &Ostream) { | ||
| const MCOperand &Op = MI->getOperand(OpNo); | ||
| if (Op.isImm()) { | ||
| Ostream << '[' << formatHex(Op.getImm()) << ']'; | ||
| } else { | ||
| // Symbolic operand will be lowered to immediate value by linker | ||
| assert(Op.isExpr() && "Expected an expression"); | ||
| Ostream << '['; | ||
| printExpr(MAI, *Op.getExpr(), Ostream); | ||
| Ostream << ']'; | ||
| } | ||
| } | ||
|
|
||
| void LanaiInstPrinter::printHi16ImmOperand(const MCInst *MI, unsigned OpNo, | ||
| raw_ostream &Ostream) { | ||
| const MCOperand &Op = MI->getOperand(OpNo); | ||
| if (Op.isImm()) { | ||
| Ostream << formatHex(Op.getImm() << 16); | ||
| } else { | ||
| // Symbolic operand will be lowered to immediate value by linker | ||
| assert(Op.isExpr() && "Expected an expression"); | ||
| printExpr(MAI, *Op.getExpr(), Ostream); | ||
| } | ||
| } | ||
|
|
||
| void LanaiInstPrinter::printHi16AndImmOperand(const MCInst *MI, unsigned OpNo, | ||
| raw_ostream &Ostream) { | ||
| const MCOperand &Op = MI->getOperand(OpNo); | ||
| if (Op.isImm()) { | ||
| Ostream << formatHex((Op.getImm() << 16) | 0xffff); | ||
| } else { | ||
| // Symbolic operand will be lowered to immediate value by linker | ||
| assert(Op.isExpr() && "Expected an expression"); | ||
| printExpr(MAI, *Op.getExpr(), Ostream); | ||
| } | ||
| } | ||
|
|
||
| void LanaiInstPrinter::printLo16AndImmOperand(const MCInst *MI, unsigned OpNo, | ||
| raw_ostream &Ostream) { | ||
| const MCOperand &Op = MI->getOperand(OpNo); | ||
| if (Op.isImm()) { | ||
| Ostream << formatHex(0xffff0000 | Op.getImm()); | ||
| } else { | ||
| // Symbolic operand will be lowered to immediate value by linker | ||
| assert(Op.isExpr() && "Expected an expression"); | ||
| printExpr(MAI, *Op.getExpr(), Ostream); | ||
| } | ||
| } | ||
|
|
||
| static void printMemoryBaseRegister(raw_ostream &Ostream, const unsigned AluCode, | ||
| const MCOperand &RegOp) { | ||
| assert(RegOp.isReg() && "Register operand expected"); | ||
| Ostream << "["; | ||
| if (LPAC::isPreOp(AluCode)) | ||
| Ostream << "*"; | ||
| Ostream << "%" << LanaiInstPrinter::getRegisterName(RegOp.getReg()); | ||
| if (LPAC::isPostOp(AluCode)) | ||
| Ostream << "*"; | ||
| Ostream << "]"; | ||
| } | ||
|
|
||
| template <unsigned SizeInBits> | ||
| static void printMemoryImmediateOffset(const MCAsmInfo &MAI, | ||
| const MCOperand &OffsetOp, | ||
| raw_ostream &Ostream) { | ||
| assert((OffsetOp.isImm() || OffsetOp.isExpr()) && "Immediate expected"); | ||
| if (OffsetOp.isImm()) { | ||
| assert(isInt<SizeInBits>(OffsetOp.getImm()) && "Constant value truncated"); | ||
| Ostream << OffsetOp.getImm(); | ||
| } else | ||
| printExpr(MAI, *OffsetOp.getExpr(), Ostream); | ||
| } | ||
|
|
||
| void LanaiInstPrinter::printMemRiOperand(const MCInst *MI, int OpNo, | ||
| raw_ostream &Ostream, | ||
| const char *Modifier) { | ||
| const MCOperand &RegOp = MI->getOperand(OpNo); | ||
| const MCOperand &OffsetOp = MI->getOperand(OpNo + 1); | ||
| const MCOperand &AluOp = MI->getOperand(OpNo + 2); | ||
| const unsigned AluCode = AluOp.getImm(); | ||
|
|
||
| // Offset | ||
| printMemoryImmediateOffset<16>(MAI, OffsetOp, Ostream); | ||
|
|
||
| // Register | ||
| printMemoryBaseRegister(Ostream, AluCode, RegOp); | ||
| } | ||
|
|
||
| void LanaiInstPrinter::printMemRrOperand(const MCInst *MI, int OpNo, | ||
| raw_ostream &Ostream, | ||
| const char *Modifier) { | ||
| const MCOperand &RegOp = MI->getOperand(OpNo); | ||
| const MCOperand &OffsetOp = MI->getOperand(OpNo + 1); | ||
| const MCOperand &AluOp = MI->getOperand(OpNo + 2); | ||
| const unsigned AluCode = AluOp.getImm(); | ||
| assert(OffsetOp.isReg() && RegOp.isReg() && "Registers expected."); | ||
|
|
||
| // [ Base OP Offset ] | ||
| Ostream << "["; | ||
| if (LPAC::isPreOp(AluCode)) | ||
| Ostream << "*"; | ||
| Ostream << "%" << getRegisterName(RegOp.getReg()); | ||
| if (LPAC::isPostOp(AluCode)) | ||
| Ostream << "*"; | ||
| Ostream << " " << LPAC::lanaiAluCodeToString(AluCode) << " "; | ||
| Ostream << "%" << getRegisterName(OffsetOp.getReg()); | ||
| Ostream << "]"; | ||
| } | ||
|
|
||
| void LanaiInstPrinter::printMemSplsOperand(const MCInst *MI, int OpNo, | ||
| raw_ostream &Ostream, | ||
| const char *Modifier) { | ||
| const MCOperand &RegOp = MI->getOperand(OpNo); | ||
| const MCOperand &OffsetOp = MI->getOperand(OpNo + 1); | ||
| const MCOperand &AluOp = MI->getOperand(OpNo + 2); | ||
| const unsigned AluCode = AluOp.getImm(); | ||
|
|
||
| // Offset | ||
| printMemoryImmediateOffset<10>(MAI, OffsetOp, Ostream); | ||
|
|
||
| // Register | ||
| printMemoryBaseRegister(Ostream, AluCode, RegOp); | ||
| } | ||
|
|
||
| void LanaiInstPrinter::printCCOperand(const MCInst *MI, int OpNo, | ||
| raw_ostream &Ostream) { | ||
| const int CC = static_cast<const int>(MI->getOperand(OpNo).getImm()); | ||
| Ostream << lanaiCondCodeToString(static_cast<LPCC::CondCode>(CC)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| //= LanaiInstPrinter.h - Convert Lanai MCInst to asm 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 Lanai MCInst to a .s file. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H | ||
| #define LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H | ||
|
|
||
| #include "llvm/MC/MCInstPrinter.h" | ||
|
|
||
| namespace llvm { | ||
| class MCOperand; | ||
|
|
||
| class LanaiInstPrinter : public MCInstPrinter { | ||
| public: | ||
| LanaiInstPrinter(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; | ||
| void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, | ||
| const char *Modifier = 0); | ||
| void printMemRiOperand(const MCInst *MI, int OpNo, raw_ostream &O, | ||
| const char *Modifier = 0); | ||
| void printMemRrOperand(const MCInst *MI, int OpNo, raw_ostream &O, | ||
| const char *Modifier = 0); | ||
| void printMemSplsOperand(const MCInst *MI, int OpNo, raw_ostream &O, | ||
| const char *Modifier = 0); | ||
| void printCCOperand(const MCInst *MI, int OpNo, raw_ostream &O); | ||
| void printAluOperand(const MCInst *MI, int OpNo, raw_ostream &O); | ||
| void printHi16ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); | ||
| void printHi16AndImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); | ||
| void printLo16AndImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); | ||
| void printMemImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); | ||
|
|
||
| // Autogenerated by tblgen. | ||
| void printInstruction(const MCInst *MI, raw_ostream &O); | ||
| bool printAliasInstr(const MCInst *MI, raw_ostream &OS); | ||
| void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx, | ||
| unsigned PrintMethodIdx, raw_ostream &O); | ||
| static const char *getRegisterName(unsigned RegNo); | ||
| void printRegName(raw_ostream &OS, unsigned RegNo) const override; | ||
|
|
||
| private: | ||
| bool printAlias(const MCInst *MI, raw_ostream &Ostream); | ||
| bool printInst(const MCInst *MI, raw_ostream &Ostream, StringRef Alias, | ||
| unsigned OpNo0, unsigned OpnNo1); | ||
| bool printMemoryLoadIncrement(const MCInst *MI, raw_ostream &Ostream, | ||
| StringRef Opcode, int AddOffset); | ||
| bool printMemoryStoreIncrement(const MCInst *MI, raw_ostream &Ostream, | ||
| StringRef Opcode, int AddOffset); | ||
| }; | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| ;===- ./lib/Target/Lanai/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 = Lanai | ||
| parent = Target | ||
| has_asmprinter = 1 | ||
|
|
||
| [component_1] | ||
| type = Library | ||
| name = LanaiCodeGen | ||
| parent = Lanai | ||
| required_libraries = | ||
| Analysis | ||
| AsmPrinter | ||
| CodeGen | ||
| Core | ||
| LanaiAsmParser | ||
| LanaiMCTargetDesc | ||
| LanaiInfo | ||
| LanaiInstPrinter | ||
| MC | ||
| SelectionDAG | ||
| Support | ||
| Target | ||
| TransformUtils | ||
| add_to_library_groups = Lanai |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| //===-- Lanai.h - Top-level interface for Lanai 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 | ||
| // Lanai back-end. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_LANAI_LANAI_H | ||
| #define LLVM_LIB_TARGET_LANAI_LANAI_H | ||
|
|
||
| #include "LanaiAluCode.h" | ||
| #include "LanaiCondCode.h" | ||
| #include "MCTargetDesc/LanaiBaseInfo.h" | ||
| #include "MCTargetDesc/LanaiMCTargetDesc.h" | ||
| #include "llvm/CodeGen/ISDOpcodes.h" | ||
| #include "llvm/Target/TargetMachine.h" | ||
|
|
||
| namespace llvm { | ||
| class FunctionPass; | ||
| class LanaiTargetMachine; | ||
| class MachineFunctionPass; | ||
| class TargetMachine; | ||
| class formatted_raw_ostream; | ||
|
|
||
| // createLanaiISelDag - This pass converts a legalized DAG into a | ||
| // Lanai-specific DAG, ready for instruction scheduling. | ||
| FunctionPass *createLanaiISelDag(LanaiTargetMachine &TM); | ||
|
|
||
| // createLanaiDelaySlotFillerPass - This pass fills delay slots | ||
| // with useful instructions or nop's | ||
| FunctionPass *createLanaiDelaySlotFillerPass(const LanaiTargetMachine &TM); | ||
|
|
||
| // createLanaiMemAluCombinerPass - This pass combines loads/stores and | ||
| // arithmetic operations. | ||
| FunctionPass *createLanaiMemAluCombinerPass(); | ||
|
|
||
| // createLanaiSetflagAluCombinerPass - This pass combines SET_FLAG and ALU | ||
| // operations. | ||
| FunctionPass *createLanaiSetflagAluCombinerPass(); | ||
|
|
||
| extern Target TheLanaiTarget; | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_LANAI_LANAI_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| //===- Lanai.td - Describe the Lanai 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" | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Register File, Calling Conv, Instruction Descriptions | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| include "LanaiSchedule.td" | ||
| include "LanaiRegisterInfo.td" | ||
| include "LanaiCallingConv.td" | ||
| include "LanaiInstrInfo.td" | ||
|
|
||
| def LanaiInstrInfo : InstrInfo; | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Lanai processors supported. | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| def : ProcessorModel<"generic", LanaiSchedModel, []>; | ||
| def : ProcessorModel<"v11", LanaiSchedModel, []>; | ||
|
|
||
| def LanaiInstPrinter : AsmWriter { | ||
| string AsmWriterClassName = "InstPrinter"; | ||
| bit isMCAsmWriter = 1; | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Declare the target which we are implementing | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| def Lanai : Target { | ||
| // Pull in Instruction Info: | ||
| let InstructionSet = LanaiInstrInfo; | ||
| let AssemblyWriters = [LanaiInstPrinter]; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| //===-- LanaiAluCode.h - ALU operator encoding ----------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The encoding for ALU operators used in RM and RRM operands | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_LANAI_LANAIALUCODE_H | ||
| #define LLVM_LIB_TARGET_LANAI_LANAIALUCODE_H | ||
|
|
||
| #include "llvm/ADT/StringSwitch.h" | ||
| #include "llvm/CodeGen/ISDOpcodes.h" | ||
| #include "llvm/Support/ErrorHandling.h" | ||
|
|
||
| namespace llvm { | ||
| namespace LPAC { | ||
| enum AluCode { | ||
| ADD = 0x00, | ||
| ADDC = 0x01, | ||
| SUB = 0x02, | ||
| SUBB = 0x03, | ||
| AND = 0x04, | ||
| OR = 0x05, | ||
| XOR = 0x06, | ||
| SPECIAL = 0x07, | ||
|
|
||
| // Shift instructions are treated as SPECIAL when encoding the machine | ||
| // instruction, but kept distinct until lowering. The constant values are | ||
| // chosen to ease lowering. | ||
| SHL = 0x17, | ||
| SRL = 0x27, | ||
| SRA = 0x37, | ||
|
|
||
| // Indicates an unknown/unsupported operator | ||
| UNKNOWN = 0xFF, | ||
| }; | ||
|
|
||
| // Bits indicating post- and pre-operators should be tested and set using Is* | ||
| // and Make* utility functions | ||
| constexpr int Lanai_PRE_OP = 0x40; | ||
| constexpr int Lanai_POST_OP = 0x80; | ||
|
|
||
| inline static unsigned encodeLanaiAluCode(unsigned AluOp) { | ||
| unsigned const OP_ENCODING_MASK = 0x07; | ||
| return AluOp & OP_ENCODING_MASK; | ||
| } | ||
|
|
||
| inline static unsigned getAluOp(unsigned AluOp) { | ||
| unsigned const ALU_MASK = 0x3F; | ||
| return AluOp & ALU_MASK; | ||
| } | ||
|
|
||
| inline static bool isPreOp(unsigned AluOp) { return AluOp & Lanai_PRE_OP; } | ||
|
|
||
| inline static bool isPostOp(unsigned AluOp) { return AluOp & Lanai_POST_OP; } | ||
|
|
||
| inline static unsigned makePreOp(unsigned AluOp) { | ||
| assert(!isPostOp(AluOp) && "Operator can't be a post- and pre-op"); | ||
| return AluOp | Lanai_PRE_OP; | ||
| } | ||
|
|
||
| inline static unsigned makePostOp(unsigned AluOp) { | ||
| assert(!isPreOp(AluOp) && "Operator can't be a post- and pre-op"); | ||
| return AluOp | Lanai_POST_OP; | ||
| } | ||
|
|
||
| inline static bool modifiesOp(unsigned AluOp) { | ||
| return isPreOp(AluOp) | isPostOp(AluOp); | ||
| } | ||
|
|
||
| inline static const char *lanaiAluCodeToString(unsigned AluOp) { | ||
| switch (getAluOp(AluOp)) { | ||
| case ADD: | ||
| return "add"; | ||
| case ADDC: | ||
| return "addc"; | ||
| case SUB: | ||
| return "sub"; | ||
| case SUBB: | ||
| return "subb"; | ||
| case AND: | ||
| return "and"; | ||
| case OR: | ||
| return "or"; | ||
| case XOR: | ||
| return "xor"; | ||
| case SHL: | ||
| return "sh"; | ||
| case SRL: | ||
| return "sh"; | ||
| case SRA: | ||
| return "sha"; | ||
| default: | ||
| llvm_unreachable("Invalid ALU code."); | ||
| } | ||
| } | ||
|
|
||
| inline static AluCode stringToLanaiAluCode(StringRef S) { | ||
| return StringSwitch<AluCode>(S) | ||
| .Case("add", ADD) | ||
| .Case("addc", ADDC) | ||
| .Case("sub", SUB) | ||
| .Case("subb", SUBB) | ||
| .Case("and", AND) | ||
| .Case("or", OR) | ||
| .Case("xor", XOR) | ||
| .Case("sh", SHL) | ||
| .Case("srl", SRL) | ||
| .Case("sha", SRA) | ||
| .Default(UNKNOWN); | ||
| } | ||
|
|
||
| inline static AluCode isdToLanaiAluCode(ISD::NodeType Node_type) { | ||
| switch (Node_type) { | ||
| case ISD::ADD: | ||
| return AluCode::ADD; | ||
| case ISD::ADDE: | ||
| return AluCode::ADDC; | ||
| case ISD::SUB: | ||
| return AluCode::SUB; | ||
| case ISD::SUBE: | ||
| return AluCode::SUBB; | ||
| case ISD::AND: | ||
| return AluCode::AND; | ||
| case ISD::OR: | ||
| return AluCode::OR; | ||
| case ISD::XOR: | ||
| return AluCode::XOR; | ||
| case ISD::SHL: | ||
| return AluCode::SHL; | ||
| case ISD::SRL: | ||
| return AluCode::SRL; | ||
| case ISD::SRA: | ||
| return AluCode::SRA; | ||
| default: | ||
| return AluCode::UNKNOWN; | ||
| } | ||
| } | ||
| } // namespace LPAC | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_LANAI_LANAIALUCODE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,252 @@ | ||
| //===-- LanaiAsmPrinter.cpp - Lanai 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 Lanai assembly language. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "Lanai.h" | ||
| #include "InstPrinter/LanaiInstPrinter.h" | ||
| #include "LanaiInstrInfo.h" | ||
| #include "LanaiMCInstLower.h" | ||
| #include "LanaiTargetMachine.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/MCInstBuilder.h" | ||
| #include "llvm/MC/MCStreamer.h" | ||
| #include "llvm/MC/MCSymbol.h" | ||
| #include "llvm/Support/TargetRegistry.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
|
|
||
| #define DEBUG_TYPE "asm-printer" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| namespace { | ||
| class LanaiAsmPrinter : public AsmPrinter { | ||
| public: | ||
| explicit LanaiAsmPrinter(TargetMachine &TM, | ||
| std::unique_ptr<MCStreamer> Streamer) | ||
| : AsmPrinter(TM, std::move(Streamer)) {} | ||
|
|
||
| const char *getPassName() const override { return "Lanai Assembly Printer"; } | ||
|
|
||
| void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, | ||
| const char *Modifier = 0); | ||
| bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | ||
| unsigned AsmVariant, const char *ExtraCode, | ||
| raw_ostream &O) override; | ||
| void EmitInstruction(const MachineInstr *MI) override; | ||
| bool isBlockOnlyReachableByFallthrough( | ||
| const MachineBasicBlock *MBB) const override; | ||
|
|
||
| private: | ||
| void customEmitInstruction(const MachineInstr *MI); | ||
| void emitCallInstruction(const MachineInstr *MI); | ||
| }; | ||
| } // end of anonymous namespace | ||
|
|
||
| void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, | ||
| raw_ostream &O, const char *Modifier) { | ||
| const MachineOperand &MO = MI->getOperand(OpNum); | ||
| unsigned TF = MO.getTargetFlags(); | ||
|
|
||
| switch (MO.getType()) { | ||
| case MachineOperand::MO_Register: | ||
| O << LanaiInstPrinter::getRegisterName(MO.getReg()); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_Immediate: | ||
| O << MO.getImm(); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_MachineBasicBlock: | ||
| O << *MO.getMBB()->getSymbol(); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_GlobalAddress: | ||
| if (TF == LanaiII::MO_PLT) | ||
| O << "plt(" << *getSymbol(MO.getGlobal()) << ")"; | ||
| else | ||
| O << *getSymbol(MO.getGlobal()); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_BlockAddress: { | ||
| MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); | ||
| O << BA->getName(); | ||
| break; | ||
| } | ||
|
|
||
| case MachineOperand::MO_ExternalSymbol: | ||
| if (TF == LanaiII::MO_PLT) | ||
| O << "plt(" << *GetExternalSymbolSymbol(MO.getSymbolName()) << ")"; | ||
| else | ||
| O << *GetExternalSymbolSymbol(MO.getSymbolName()); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_JumpTableIndex: | ||
| O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_' | ||
| << MO.getIndex(); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_ConstantPoolIndex: | ||
| O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_' | ||
| << MO.getIndex(); | ||
| return; | ||
|
|
||
| default: | ||
| llvm_unreachable("<unknown operand type>"); | ||
| } | ||
| } | ||
|
|
||
| // PrintAsmOperand - Print out an operand for an inline asm expression. | ||
| // | ||
| bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | ||
| unsigned AsmVariant, | ||
| const char *ExtraCode, raw_ostream &O) { | ||
| // Does this asm operand have a single letter operand modifier? | ||
| if (ExtraCode && ExtraCode[0]) { | ||
| if (ExtraCode[1]) | ||
| return true; // Unknown modifier. | ||
|
|
||
| switch (ExtraCode[0]) { | ||
| // The highest-numbered register of a pair. | ||
| case 'H': { | ||
| if (OpNo == 0) | ||
| return true; | ||
| const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1); | ||
| if (!FlagsOP.isImm()) | ||
| return true; | ||
| unsigned Flags = FlagsOP.getImm(); | ||
| unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags); | ||
| if (NumVals != 2) | ||
| return true; | ||
| unsigned RegOp = OpNo + 1; | ||
| if (RegOp >= MI->getNumOperands()) | ||
| return true; | ||
| const MachineOperand &MO = MI->getOperand(RegOp); | ||
| if (!MO.isReg()) | ||
| return true; | ||
| unsigned Reg = MO.getReg(); | ||
| O << LanaiInstPrinter::getRegisterName(Reg); | ||
| return false; | ||
| } | ||
| default: | ||
| return true; // Unknown modifier. | ||
| } | ||
| } | ||
| printOperand(MI, OpNo, O); | ||
| return false; | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| void LanaiAsmPrinter::emitCallInstruction(const MachineInstr *MI) { | ||
| assert((MI->getOpcode() == Lanai::CALL || MI->getOpcode() == Lanai::CALLR) && | ||
| "Unsupported call function"); | ||
|
|
||
| LanaiMCInstLower MCInstLowering(OutContext, *Mang, *this); | ||
| MCSubtargetInfo STI = getSubtargetInfo(); | ||
| // Insert save rca instruction immediately before the call. | ||
| // TODO: We should generate a pc-relative mov instruction here instead | ||
| // of pc + 16 (should be mov .+16 %rca). | ||
| OutStreamer->EmitInstruction(MCInstBuilder(Lanai::ADD_I_LO) | ||
| .addReg(Lanai::RCA) | ||
| .addReg(Lanai::PC) | ||
| .addImm(16), | ||
| STI); | ||
|
|
||
| // Push rca onto the stack. | ||
| // st %rca, [--%sp] | ||
| OutStreamer->EmitInstruction(MCInstBuilder(Lanai::SW_RI) | ||
| .addReg(Lanai::RCA) | ||
| .addReg(Lanai::SP) | ||
| .addImm(-4) | ||
| .addImm(LPAC::makePreOp(LPAC::ADD)), | ||
| STI); | ||
|
|
||
| // Lower the call instruction. | ||
| if (MI->getOpcode() == Lanai::CALL) { | ||
| MCInst TmpInst; | ||
| MCInstLowering.Lower(MI, TmpInst); | ||
| TmpInst.setOpcode(Lanai::BT); | ||
| OutStreamer->EmitInstruction(TmpInst, STI); | ||
| } else { | ||
| OutStreamer->EmitInstruction(MCInstBuilder(Lanai::ADD_R) | ||
| .addReg(Lanai::PC) | ||
| .addReg(MI->getOperand(0).getReg()) | ||
| .addReg(Lanai::R0) | ||
| .addImm(LPCC::ICC_T), | ||
| STI); | ||
| } | ||
| } | ||
|
|
||
| void LanaiAsmPrinter::customEmitInstruction(const MachineInstr *MI) { | ||
| LanaiMCInstLower MCInstLowering(OutContext, *Mang, *this); | ||
| MCSubtargetInfo STI = getSubtargetInfo(); | ||
| MCInst TmpInst; | ||
| MCInstLowering.Lower(MI, TmpInst); | ||
| OutStreamer->EmitInstruction(TmpInst, STI); | ||
| } | ||
|
|
||
| void LanaiAsmPrinter::EmitInstruction(const MachineInstr *MI) { | ||
| MachineBasicBlock::const_instr_iterator I = MI->getIterator(); | ||
| MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); | ||
|
|
||
| do { | ||
| if (I->isCall()) { | ||
| emitCallInstruction(&*I); | ||
| continue; | ||
| } | ||
|
|
||
| customEmitInstruction(&*I); | ||
| } while ((++I != E) && I->isInsideBundle()); | ||
| } | ||
|
|
||
| // isBlockOnlyReachableByFallthough - Return true if the basic block has | ||
| // exactly one predecessor and the control transfer mechanism between | ||
| // the predecessor and this block is a fall-through. | ||
| // FIXME: could the overridden cases be handled in AnalyzeBranch? | ||
| bool LanaiAsmPrinter::isBlockOnlyReachableByFallthrough( | ||
| const MachineBasicBlock *MBB) const { | ||
| // The predecessor has to be immediately before this block. | ||
| const MachineBasicBlock *Pred = *MBB->pred_begin(); | ||
|
|
||
| // If the predecessor is a switch statement, assume a jump table | ||
| // implementation, so it is not a fall through. | ||
| if (const BasicBlock *B = Pred->getBasicBlock()) | ||
| if (isa<SwitchInst>(B->getTerminator())) | ||
| return false; | ||
|
|
||
| // Check default implementation | ||
| if (!AsmPrinter::isBlockOnlyReachableByFallthrough(MBB)) | ||
| return false; | ||
|
|
||
| // Otherwise, check the last instruction. | ||
| // Check if the last terminator is an unconditional branch. | ||
| MachineBasicBlock::const_iterator I = Pred->end(); | ||
| while (I != Pred->begin() && !(--I)->isTerminator()) { | ||
| } | ||
|
|
||
| return !I->isBarrier(); | ||
| } | ||
|
|
||
| // Force static initialization. | ||
| extern "C" void LLVMInitializeLanaiAsmPrinter() { | ||
| RegisterAsmPrinter<LanaiAsmPrinter> X(TheLanaiTarget); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| //===- LanaiCallingConv.td - Calling Conventions Lanai -------*- 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 Lanai architectures. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Return Value Calling Conventions | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // Lanai 32-bit C Calling convention. | ||
| def CC_Lanai32 : CallingConv<[ | ||
| // Promote i8/i16 args to i32 | ||
| CCIfType<[i8, i16], CCPromoteToType<i32>>, | ||
|
|
||
| // Put argument in registers if marked 'inreg' and not a vararg call. | ||
| CCIfNotVarArg<CCIfInReg<CCIfType<[i32], | ||
| CCAssignToReg<[R6, R7, R18, R19]>>>>, | ||
|
|
||
| // Otherwise they are assigned to the stack in 4-byte aligned units. | ||
| CCAssignToStack<4, 4> | ||
| ]>; | ||
|
|
||
| // Lanai 32-bit Fast Calling convention. | ||
| def CC_Lanai32_Fast : CallingConv<[ | ||
| // Promote i8/i16 args to i32 | ||
| CCIfType<[ i8, i16 ], CCPromoteToType<i32>>, | ||
|
|
||
| // Put arguments in registers. | ||
| CCIfNotVarArg<CCIfType<[i32], CCAssignToReg<[ R6, R7, R18, R19 ]>>>, | ||
|
|
||
| // Otherwise they are assigned to the stack in 4-byte aligned units. | ||
| CCAssignToStack<4, 4> | ||
| ]>; | ||
|
|
||
| // Lanai 32-bit C return-value convention. | ||
| def RetCC_Lanai32 : CallingConv<[ | ||
| // Specify two registers to allow returning 64-bit results that have already | ||
| // been lowered to 2 32-bit values. | ||
| CCIfType<[i32], CCAssignToReg<[RV, R9]>> | ||
| ]>; | ||
|
|
||
| def CSR: CalleeSavedRegs<(add)>; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| // The encoding used for conditional codes used in BR instructions | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_LANAI_LANAICONDCODE_H | ||
| #define LLVM_LIB_TARGET_LANAI_LANAICONDCODE_H | ||
|
|
||
| #include "llvm/ADT/StringSwitch.h" | ||
|
|
||
| namespace llvm { | ||
| namespace LPCC { | ||
| enum CondCode { | ||
| ICC_T = 0, // true | ||
| ICC_F = 1, // false | ||
| ICC_HI = 2, // high | ||
| ICC_UGT = 2, // unsigned greater than | ||
| ICC_LS = 3, // low or same | ||
| ICC_ULE = 3, // unsigned less than or equal | ||
| ICC_CC = 4, // carry cleared | ||
| ICC_ULT = 4, // unsigned less than | ||
| ICC_CS = 5, // carry set | ||
| ICC_UGE = 5, // unsigned greater than or equal | ||
| ICC_NE = 6, // not equal | ||
| ICC_EQ = 7, // equal | ||
| ICC_VC = 8, // oVerflow cleared | ||
| ICC_VS = 9, // oVerflow set | ||
| ICC_PL = 10, // plus | ||
| ICC_MI = 11, // minus | ||
| ICC_GE = 12, // greater than or equal | ||
| ICC_LT = 13, // less than | ||
| ICC_GT = 14, // greater than | ||
| ICC_LE = 15, // less than or equal | ||
| UNKNOWN | ||
| }; | ||
|
|
||
| inline static StringRef lanaiCondCodeToString(LPCC::CondCode CC) { | ||
| switch (CC) { | ||
| case LPCC::ICC_T: | ||
| return "t"; // true | ||
| case LPCC::ICC_F: | ||
| return "f"; // false | ||
| case LPCC::ICC_NE: | ||
| return "ne"; // not equal | ||
| case LPCC::ICC_EQ: | ||
| return "eq"; // equal | ||
| case LPCC::ICC_VC: | ||
| return "vc"; // oVerflow cleared | ||
| case LPCC::ICC_VS: | ||
| return "vs"; // oVerflow set | ||
| case LPCC::ICC_PL: | ||
| return "pl"; // plus | ||
| case LPCC::ICC_MI: | ||
| return "mi"; // minus | ||
| case LPCC::ICC_GE: | ||
| return "ge"; // greater than or equal | ||
| case LPCC::ICC_LT: | ||
| return "lt"; // less than | ||
| case LPCC::ICC_GT: | ||
| return "gt"; // greater than | ||
| case LPCC::ICC_LE: | ||
| return "le"; // less than or equal | ||
| case LPCC::ICC_UGT: | ||
| return "ugt"; // high | unsigned greater than | ||
| case LPCC::ICC_ULE: | ||
| return "ule"; // low or same | unsigned less or equal | ||
| case LPCC::ICC_ULT: | ||
| return "ult"; // carry cleared | unsigned less than | ||
| case LPCC::ICC_UGE: | ||
| return "uge"; // carry set | unsigned than or equal | ||
| default: | ||
| llvm_unreachable("Invalid cond code"); | ||
| } | ||
| } | ||
|
|
||
| inline static CondCode suffixToLanaiCondCode(StringRef S) { | ||
| return StringSwitch<CondCode>(S) | ||
| .EndsWith("f", LPCC::ICC_F) | ||
| .EndsWith("hi", LPCC::ICC_HI) | ||
| .EndsWith("ugt", LPCC::ICC_UGT) | ||
| .EndsWith("ls", LPCC::ICC_LS) | ||
| .EndsWith("ule", LPCC::ICC_ULE) | ||
| .EndsWith("cc", LPCC::ICC_CC) | ||
| .EndsWith("ult", LPCC::ICC_ULT) | ||
| .EndsWith("cs", LPCC::ICC_CS) | ||
| .EndsWith("uge", LPCC::ICC_UGE) | ||
| .EndsWith("ne", LPCC::ICC_NE) | ||
| .EndsWith("eq", LPCC::ICC_EQ) | ||
| .EndsWith("vc", LPCC::ICC_VC) | ||
| .EndsWith("vs", LPCC::ICC_VS) | ||
| .EndsWith("pl", LPCC::ICC_PL) | ||
| .EndsWith("mi", LPCC::ICC_MI) | ||
| .EndsWith("ge", LPCC::ICC_GE) | ||
| .EndsWith("lt", LPCC::ICC_LT) | ||
| .EndsWith("gt", LPCC::ICC_GT) | ||
| .EndsWith("le", LPCC::ICC_LE) | ||
| .EndsWith("t", LPCC::ICC_T) // Has to be after others with suffix t | ||
| .Default(LPCC::UNKNOWN); | ||
| } | ||
| } // namespace LPCC | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_LANAI_LANAICONDCODE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,250 @@ | ||
| //===-- LanaiDelaySlotFiller.cpp - Lanai delay slot filler ----------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Simple pass to fills delay slots with useful instructions. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "Lanai.h" | ||
| #include "LanaiTargetMachine.h" | ||
| #include "llvm/ADT/SmallSet.h" | ||
| #include "llvm/ADT/Statistic.h" | ||
| #include "llvm/CodeGen/MachineFunctionPass.h" | ||
| #include "llvm/CodeGen/MachineInstrBuilder.h" | ||
| #include "llvm/Support/CommandLine.h" | ||
| #include "llvm/Target/TargetInstrInfo.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "delay-slot-filler" | ||
|
|
||
| STATISTIC(FilledSlots, "Number of delay slots filled"); | ||
|
|
||
| static cl::opt<bool> | ||
| NopDelaySlotFiller("lanai-nop-delay-filler", cl::init(false), | ||
| cl::desc("Fill Lanai delay slots with NOPs."), | ||
| cl::Hidden); | ||
|
|
||
| namespace { | ||
| struct Filler : public MachineFunctionPass { | ||
| // Target machine description which we query for reg. names, data | ||
| // layout, etc. | ||
| const TargetInstrInfo *TII; | ||
| const TargetRegisterInfo *TRI; | ||
| MachineBasicBlock::instr_iterator LastFiller; | ||
|
|
||
| static char ID; | ||
| explicit Filler() : MachineFunctionPass(ID) {} | ||
|
|
||
| const char *getPassName() const override { return "Lanai Delay Slot Filler"; } | ||
|
|
||
| bool runOnMachineBasicBlock(MachineBasicBlock &MBB); | ||
|
|
||
| bool runOnMachineFunction(MachineFunction &MF) override { | ||
| const LanaiSubtarget &Subtarget = MF.getSubtarget<LanaiSubtarget>(); | ||
| TII = Subtarget.getInstrInfo(); | ||
| TRI = Subtarget.getRegisterInfo(); | ||
|
|
||
| bool Changed = false; | ||
| for (MachineFunction::iterator FI = MF.begin(), FE = MF.end(); FI != FE; | ||
| ++FI) | ||
| Changed |= runOnMachineBasicBlock(*FI); | ||
| return Changed; | ||
| } | ||
|
|
||
| void insertDefsUses(MachineBasicBlock::instr_iterator MI, | ||
| SmallSet<unsigned, 32> &RegDefs, | ||
| SmallSet<unsigned, 32> &RegUses); | ||
|
|
||
| bool isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg); | ||
|
|
||
| bool delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad, | ||
| bool &SawStore, SmallSet<unsigned, 32> &RegDefs, | ||
| SmallSet<unsigned, 32> &RegUses); | ||
|
|
||
| bool findDelayInstr(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::instr_iterator Slot, | ||
| MachineBasicBlock::instr_iterator &Filler); | ||
| }; | ||
| char Filler::ID = 0; | ||
| } // end of anonymous namespace | ||
|
|
||
| // createLanaiDelaySlotFillerPass - Returns a pass that fills in delay | ||
| // slots in Lanai MachineFunctions | ||
| FunctionPass * | ||
| llvm::createLanaiDelaySlotFillerPass(const LanaiTargetMachine &tm) { | ||
| return new Filler(); | ||
| } | ||
|
|
||
| // runOnMachineBasicBlock - Fill in delay slots for the given basic block. | ||
| // There is one or two delay slot per delayed instruction. | ||
| bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { | ||
| bool Changed = false; | ||
| LastFiller = MBB.instr_end(); | ||
|
|
||
| for (MachineBasicBlock::instr_iterator I = MBB.instr_begin(); | ||
| I != MBB.instr_end(); ++I) { | ||
| if (I->getDesc().hasDelaySlot()) { | ||
| MachineBasicBlock::instr_iterator InstrWithSlot = I; | ||
| MachineBasicBlock::instr_iterator J = I; | ||
|
|
||
| // Treat RET specially as it is only instruction with 2 delay slots | ||
| // generated while all others generated have 1 delay slot. | ||
| if (I->getOpcode() == Lanai::RET) { | ||
| // RET is generated as part of epilogue generation and hence we know | ||
| // what the two instructions preceding it are and that it is safe to | ||
| // insert RET above them. | ||
| MachineBasicBlock::reverse_instr_iterator RI(I); | ||
| assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() && | ||
| RI->getOperand(0).getReg() == Lanai::FP && | ||
| RI->getOperand(1).isReg() && | ||
| RI->getOperand(1).getReg() == Lanai::FP && | ||
| RI->getOperand(2).isImm() && RI->getOperand(2).getImm() == -8); | ||
| ++RI; | ||
| assert(RI->getOpcode() == Lanai::ADD_I_LO && | ||
| RI->getOperand(0).isReg() && | ||
| RI->getOperand(0).getReg() == Lanai::SP && | ||
| RI->getOperand(1).isReg() && | ||
| RI->getOperand(1).getReg() == Lanai::FP); | ||
| ++RI; | ||
| MachineBasicBlock::instr_iterator FI(RI.base()); | ||
| MBB.splice(std::next(I), &MBB, FI, I); | ||
| FilledSlots += 2; | ||
| } else { | ||
| if (!NopDelaySlotFiller && findDelayInstr(MBB, I, J)) { | ||
| MBB.splice(std::next(I), &MBB, J); | ||
| } else { | ||
| BuildMI(MBB, std::next(I), DebugLoc(), TII->get(Lanai::NOP)); | ||
| } | ||
| ++FilledSlots; | ||
| } | ||
|
|
||
| Changed = true; | ||
| // Record the filler instruction that filled the delay slot. | ||
| // The instruction after it will be visited in the next iteration. | ||
| LastFiller = ++I; | ||
|
|
||
| // Bundle the delay slot filler to InstrWithSlot so that the machine | ||
| // verifier doesn't expect this instruction to be a terminator. | ||
| MIBundleBuilder(MBB, InstrWithSlot, std::next(LastFiller)); | ||
| } | ||
| } | ||
| return Changed; | ||
| } | ||
|
|
||
| bool Filler::findDelayInstr(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::instr_iterator Slot, | ||
| MachineBasicBlock::instr_iterator &Filler) { | ||
| SmallSet<unsigned, 32> RegDefs; | ||
| SmallSet<unsigned, 32> RegUses; | ||
|
|
||
| insertDefsUses(Slot, RegDefs, RegUses); | ||
|
|
||
| bool SawLoad = false; | ||
| bool SawStore = false; | ||
|
|
||
| for (MachineBasicBlock::reverse_instr_iterator I(Slot); I != MBB.instr_rend(); | ||
| ++I) { | ||
| // skip debug value | ||
| if (I->isDebugValue()) | ||
| continue; | ||
|
|
||
| // Convert to forward iterator. | ||
| MachineBasicBlock::instr_iterator FI(std::next(I).base()); | ||
|
|
||
| if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() || | ||
| FI == LastFiller || I->isPseudo()) | ||
| break; | ||
|
|
||
| if (delayHasHazard(FI, SawLoad, SawStore, RegDefs, RegUses)) { | ||
| insertDefsUses(FI, RegDefs, RegUses); | ||
| continue; | ||
| } | ||
| Filler = FI; | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| bool Filler::delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad, | ||
| bool &SawStore, SmallSet<unsigned, 32> &RegDefs, | ||
| SmallSet<unsigned, 32> &RegUses) { | ||
| if (MI->isImplicitDef() || MI->isKill()) | ||
| return true; | ||
|
|
||
| // Loads or stores cannot be moved past a store to the delay slot | ||
| // and stores cannot be moved past a load. | ||
| if (MI->mayLoad()) { | ||
| if (SawStore) | ||
| return true; | ||
| SawLoad = true; | ||
| } | ||
|
|
||
| if (MI->mayStore()) { | ||
| if (SawStore) | ||
| return true; | ||
| SawStore = true; | ||
| if (SawLoad) | ||
| return true; | ||
| } | ||
|
|
||
| assert((!MI->isCall() && !MI->isReturn()) && | ||
| "Cannot put calls or returns in delay slot."); | ||
|
|
||
| for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) { | ||
| const MachineOperand &MO = MI->getOperand(I); | ||
| unsigned Reg; | ||
|
|
||
| if (!MO.isReg() || !(Reg = MO.getReg())) | ||
| continue; // skip | ||
|
|
||
| if (MO.isDef()) { | ||
| // check whether Reg is defined or used before delay slot. | ||
| if (isRegInSet(RegDefs, Reg) || isRegInSet(RegUses, Reg)) | ||
| return true; | ||
| } | ||
| if (MO.isUse()) { | ||
| // check whether Reg is defined before delay slot. | ||
| if (isRegInSet(RegDefs, Reg)) | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| // Insert Defs and Uses of MI into the sets RegDefs and RegUses. | ||
| void Filler::insertDefsUses(MachineBasicBlock::instr_iterator MI, | ||
| SmallSet<unsigned, 32> &RegDefs, | ||
| SmallSet<unsigned, 32> &RegUses) { | ||
| // If MI is a call or return, just examine the explicit non-variadic operands. | ||
| MCInstrDesc MCID = MI->getDesc(); | ||
| unsigned E = MI->isCall() || MI->isReturn() ? MCID.getNumOperands() | ||
| : MI->getNumOperands(); | ||
| for (unsigned I = 0; I != E; ++I) { | ||
| const MachineOperand &MO = MI->getOperand(I); | ||
| unsigned Reg; | ||
|
|
||
| if (!MO.isReg() || !(Reg = MO.getReg())) | ||
| continue; | ||
|
|
||
| if (MO.isDef()) | ||
| RegDefs.insert(Reg); | ||
| else if (MO.isUse()) | ||
| RegUses.insert(Reg); | ||
| } | ||
| } | ||
|
|
||
| // Returns true if the Reg or its alias is in the RegSet. | ||
| bool Filler::isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg) { | ||
| // Check Reg and all aliased Registers. | ||
| for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) | ||
| if (RegSet.count(*AI)) | ||
| return true; | ||
| return false; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,220 @@ | ||
| //===-- LanaiFrameLowering.cpp - Lanai Frame Information ------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file contains the Lanai implementation of TargetFrameLowering class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "LanaiFrameLowering.h" | ||
|
|
||
| #include "LanaiInstrInfo.h" | ||
| #include "LanaiMachineFunctionInfo.h" | ||
| #include "LanaiSubtarget.h" | ||
| #include "llvm/CodeGen/MachineFrameInfo.h" | ||
| #include "llvm/CodeGen/MachineFunction.h" | ||
| #include "llvm/CodeGen/MachineInstrBuilder.h" | ||
| #include "llvm/CodeGen/MachineRegisterInfo.h" | ||
| #include "llvm/IR/Function.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| // Determines the size of the frame and maximum call frame size. | ||
| void LanaiFrameLowering::determineFrameLayout(MachineFunction &MF) const { | ||
| MachineFrameInfo *MFI = MF.getFrameInfo(); | ||
| const LanaiRegisterInfo *LRI = STI.getRegisterInfo(); | ||
|
|
||
| // Get the number of bytes to allocate from the FrameInfo. | ||
| unsigned FrameSize = MFI->getStackSize(); | ||
|
|
||
| // Get the alignment. | ||
| unsigned StackAlign = LRI->needsStackRealignment(MF) ? MFI->getMaxAlignment() | ||
| : getStackAlignment(); | ||
|
|
||
| // Get the maximum call frame size of all the calls. | ||
| unsigned MaxCallFrameSize = MFI->getMaxCallFrameSize(); | ||
|
|
||
| // If we have dynamic alloca then MaxCallFrameSize needs to be aligned so | ||
| // that allocations will be aligned. | ||
| if (MFI->hasVarSizedObjects()) | ||
| MaxCallFrameSize = alignTo(MaxCallFrameSize, StackAlign); | ||
|
|
||
| // Update maximum call frame size. | ||
| MFI->setMaxCallFrameSize(MaxCallFrameSize); | ||
|
|
||
| // Include call frame size in total. | ||
| if (!(hasReservedCallFrame(MF) && MFI->adjustsStack())) | ||
| FrameSize += MaxCallFrameSize; | ||
|
|
||
| // Make sure the frame is aligned. | ||
| FrameSize = alignTo(FrameSize, StackAlign); | ||
|
|
||
| // Update frame info. | ||
| MFI->setStackSize(FrameSize); | ||
| } | ||
|
|
||
| // Iterates through each basic block in a machine function and replaces | ||
| // ADJDYNALLOC pseudo instructions with a Lanai:ADDI with the | ||
| // maximum call frame size as the immediate. | ||
| void LanaiFrameLowering::replaceAdjDynAllocPseudo(MachineFunction &MF) const { | ||
| const LanaiInstrInfo &LII = | ||
| *static_cast<const LanaiInstrInfo *>(STI.getInstrInfo()); | ||
| unsigned MaxCallFrameSize = MF.getFrameInfo()->getMaxCallFrameSize(); | ||
|
|
||
| for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); MBB != E; | ||
| ++MBB) { | ||
| MachineBasicBlock::iterator MBBI = MBB->begin(); | ||
| while (MBBI != MBB->end()) { | ||
| MachineInstr *MI = MBBI++; | ||
| if (MI->getOpcode() == Lanai::ADJDYNALLOC) { | ||
| DebugLoc DL = MI->getDebugLoc(); | ||
| unsigned Dst = MI->getOperand(0).getReg(); | ||
| unsigned Src = MI->getOperand(1).getReg(); | ||
|
|
||
| BuildMI(*MBB, MI, DL, LII.get(Lanai::ADD_I_LO), Dst) | ||
| .addReg(Src) | ||
| .addImm(MaxCallFrameSize); | ||
| MI->eraseFromParent(); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Generates the following sequence for function entry: | ||
| // st %fp,-4[*%sp] !push old FP | ||
| // add %sp,8,%fp !generate new FP | ||
| // sub %sp,0x4,%sp !allocate stack space (as needed) | ||
| void LanaiFrameLowering::emitPrologue(MachineFunction &MF, | ||
| MachineBasicBlock &MBB) const { | ||
| assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); | ||
|
|
||
| MachineFrameInfo *MFI = MF.getFrameInfo(); | ||
| const LanaiInstrInfo &LII = | ||
| *static_cast<const LanaiInstrInfo *>(STI.getInstrInfo()); | ||
| MachineBasicBlock::iterator MBBI = MBB.begin(); | ||
|
|
||
| // Debug location must be unknown since the first debug location is used | ||
| // to determine the end of the prologue. | ||
| DebugLoc DL; | ||
|
|
||
| // Determine the correct frame layout | ||
| determineFrameLayout(MF); | ||
|
|
||
| // FIXME: This appears to be overallocating. Needs investigation. | ||
| // Get the number of bytes to allocate from the FrameInfo. | ||
| unsigned StackSize = MFI->getStackSize(); | ||
|
|
||
| // Push old FP | ||
| // st %fp,-4[*%sp] | ||
| BuildMI(MBB, MBBI, DL, LII.get(Lanai::SW_RI)) | ||
| .addReg(Lanai::FP) | ||
| .addReg(Lanai::SP) | ||
| .addImm(-4) | ||
| .addImm(LPAC::makePreOp(LPAC::ADD)) | ||
| .setMIFlag(MachineInstr::FrameSetup); | ||
|
|
||
| // Generate new FP | ||
| // add %sp,8,%fp | ||
| BuildMI(MBB, MBBI, DL, LII.get(Lanai::ADD_I_LO), Lanai::FP) | ||
| .addReg(Lanai::SP) | ||
| .addImm(8) | ||
| .setMIFlag(MachineInstr::FrameSetup); | ||
|
|
||
| // Allocate space on the stack if needed | ||
| // sub %sp,StackSize,%sp | ||
| if (StackSize != 0) { | ||
| BuildMI(MBB, MBBI, DL, LII.get(Lanai::SUB_I_LO), Lanai::SP) | ||
| .addReg(Lanai::SP) | ||
| .addImm(StackSize) | ||
| .setMIFlag(MachineInstr::FrameSetup); | ||
| } | ||
|
|
||
| // Replace ADJDYNANALLOC | ||
| if (MFI->hasVarSizedObjects()) | ||
| replaceAdjDynAllocPseudo(MF); | ||
| } | ||
|
|
||
| void LanaiFrameLowering::eliminateCallFramePseudoInstr( | ||
| MachineFunction &MF, MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator I) const { | ||
| // Discard ADJCALLSTACKDOWN, ADJCALLSTACKUP instructions. | ||
| MBB.erase(I); | ||
| } | ||
|
|
||
| // The function epilogue should not depend on the current stack pointer! | ||
| // It should use the frame pointer only. This is mandatory because | ||
| // of alloca; we also take advantage of it to omit stack adjustments | ||
| // before returning. | ||
| // | ||
| // Note that when we go to restore the preserved register values we must | ||
| // not try to address their slots by using offsets from the stack pointer. | ||
| // That's because the stack pointer may have been moved during the function | ||
| // execution due to a call to alloca(). Rather, we must restore all | ||
| // preserved registers via offsets from the frame pointer value. | ||
| // | ||
| // Note also that when the current frame is being "popped" (by adjusting | ||
| // the value of the stack pointer) on function exit, we must (for the | ||
| // sake of alloca) set the new value of the stack pointer based upon | ||
| // the current value of the frame pointer. We can't just add what we | ||
| // believe to be the (static) frame size to the stack pointer because | ||
| // if we did that, and alloca() had been called during this function, | ||
| // we would end up returning *without* having fully deallocated all of | ||
| // the space grabbed by alloca. If that happened, and a function | ||
| // containing one or more alloca() calls was called over and over again, | ||
| // then the stack would grow without limit! | ||
| // | ||
| // RET is lowered to | ||
| // ld -4[%fp],%pc # modify %pc (two delay slots) | ||
| // as the return address is in the stack frame and mov to pc is allowed. | ||
| // emitEpilogue emits | ||
| // mov %fp,%sp # restore the stack pointer | ||
| // ld -8[%fp],%fp # restore the caller's frame pointer | ||
| // before RET and the delay slot filler will move RET such that these | ||
| // instructions execute in the delay slots of the load to PC. | ||
| void LanaiFrameLowering::emitEpilogue(MachineFunction &MF, | ||
| MachineBasicBlock &MBB) const { | ||
| MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); | ||
| const LanaiInstrInfo &LII = | ||
| *static_cast<const LanaiInstrInfo *>(STI.getInstrInfo()); | ||
| DebugLoc DL = MBBI->getDebugLoc(); | ||
|
|
||
| // Restore the stack pointer using the callee's frame pointer value. | ||
| BuildMI(MBB, MBBI, DL, LII.get(Lanai::ADD_I_LO), Lanai::SP) | ||
| .addReg(Lanai::FP) | ||
| .addImm(0); | ||
|
|
||
| // Restore the frame pointer from the stack. | ||
| BuildMI(MBB, MBBI, DL, LII.get(Lanai::LDW_RI), Lanai::FP) | ||
| .addReg(Lanai::FP) | ||
| .addImm(-8) | ||
| .addImm(LPAC::ADD); | ||
| } | ||
|
|
||
| void LanaiFrameLowering::determineCalleeSaves(MachineFunction &MF, | ||
| BitVector &SavedRegs, | ||
| RegScavenger *RS) const { | ||
| TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); | ||
|
|
||
| MachineFrameInfo *MFI = MF.getFrameInfo(); | ||
| const LanaiRegisterInfo *LRI = | ||
| static_cast<const LanaiRegisterInfo *>(STI.getRegisterInfo()); | ||
| int Offset = -4; | ||
|
|
||
| // Reserve 4 bytes for the saved RCA | ||
| MFI->CreateFixedObject(4, Offset, true); | ||
| Offset -= 4; | ||
|
|
||
| // Reserve 4 bytes for the saved FP | ||
| MFI->CreateFixedObject(4, Offset, true); | ||
| Offset -= 4; | ||
|
|
||
| if (LRI->hasBasePointer(MF)) { | ||
| MFI->CreateFixedObject(4, Offset, true); | ||
| SavedRegs.reset(LRI->getBaseRegister()); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| //===-- LanaiFrameLowering.h - Define frame lowering for Lanai --*- C++-*--===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This class implements Lanai-specific bits of TargetFrameLowering class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_LANAI_LANAIFRAMELOWERING_H | ||
| #define LLVM_LIB_TARGET_LANAI_LANAIFRAMELOWERING_H | ||
|
|
||
| #include "Lanai.h" | ||
| #include "llvm/Target/TargetFrameLowering.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class BitVector; | ||
| class LanaiSubtarget; | ||
|
|
||
| class LanaiFrameLowering : public TargetFrameLowering { | ||
| private: | ||
| void determineFrameLayout(MachineFunction &MF) const; | ||
| void replaceAdjDynAllocPseudo(MachineFunction &MF) const; | ||
|
|
||
| protected: | ||
| const LanaiSubtarget &STI; | ||
|
|
||
| public: | ||
| explicit LanaiFrameLowering(const LanaiSubtarget &Subtarget) | ||
| : TargetFrameLowering(StackGrowsDown, | ||
| /*StackAlignment=*/8, | ||
| /*LocalAreaOffset=*/0), | ||
| STI(Subtarget) {} | ||
|
|
||
| // 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 { return true; } | ||
|
|
||
| void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, | ||
| RegScavenger *RS = nullptr) const override; | ||
| }; | ||
|
|
||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_LANAI_LANAIFRAMELOWERING_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,325 @@ | ||
| //===-- LanaiISelDAGToDAG.cpp - A dag to dag inst selector for Lanai ------===// | ||
| // | ||
| // 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 Lanai target. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "Lanai.h" | ||
| #include "LanaiMachineFunctionInfo.h" | ||
| #include "LanaiRegisterInfo.h" | ||
| #include "LanaiSubtarget.h" | ||
| #include "LanaiTargetMachine.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; | ||
|
|
||
| #define DEBUG_TYPE "lanai-isel" | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // Instruction Selector Implementation | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // LanaiDAGToDAGISel - Lanai specific code to select Lanai machine | ||
| // instructions for SelectionDAG operations. | ||
| //===----------------------------------------------------------------------===// | ||
| namespace { | ||
|
|
||
| class LanaiDAGToDAGISel : public SelectionDAGISel { | ||
| public: | ||
| explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine) | ||
| : SelectionDAGISel(TargetMachine) {} | ||
|
|
||
| bool runOnMachineFunction(MachineFunction &MF) override { | ||
| return SelectionDAGISel::runOnMachineFunction(MF); | ||
| } | ||
|
|
||
| // Pass Name | ||
| const char *getPassName() const override { | ||
| return "Lanai DAG->DAG Pattern Instruction Selection"; | ||
| } | ||
|
|
||
| bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode, | ||
| std::vector<SDValue> &OutOps) override; | ||
|
|
||
| private: | ||
| // Include the pieces autogenerated from the target description. | ||
| #include "LanaiGenDAGISel.inc" | ||
|
|
||
| // Instruction Selection not handled by the auto-generated tablgen | ||
| SDNode *Select(SDNode *N) override; | ||
|
|
||
| // Support functions for the opcodes of Instruction Selection | ||
| // not handled by the auto-generated tablgen | ||
| SDNode *selectFrameIndex(SDNode *N); | ||
|
|
||
| // Complex Pattern for address selection. | ||
| bool selectAddrRi(SDValue Addr, SDValue &Base, SDValue &Offset, | ||
| SDValue &AluOp); | ||
| bool selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2, SDValue &AluOp); | ||
| bool selectAddrSls(SDValue Addr, SDValue &Offset); | ||
| bool selectAddrSpls(SDValue Addr, SDValue &Base, SDValue &Offset, | ||
| SDValue &AluOp); | ||
|
|
||
| // getI32Imm - Return a target constant with the specified value, of type i32. | ||
| inline SDValue getI32Imm(unsigned Imm, SDLoc DL) { | ||
| return CurDAG->getTargetConstant(Imm, DL, MVT::i32); | ||
| } | ||
|
|
||
| private: | ||
| bool selectAddrRiSpls(SDValue Addr, SDValue &Base, SDValue &Offset, | ||
| SDValue &AluOp, bool RiMode); | ||
| }; | ||
|
|
||
| bool canBeRepresentedAsSls(const ConstantSDNode &CN) { | ||
| // Fits in 21-bit signed immediate and two low-order bits are zero. | ||
| return isInt<21>(CN.getSExtValue()) && ((CN.getSExtValue() & 0x3) == 0); | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| // Helper functions for ComplexPattern used on LanaiInstrInfo | ||
| // Used on Lanai Load/Store instructions. | ||
| bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr, SDValue &Offset) { | ||
| if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) { | ||
| SDLoc DL(Addr); | ||
| // Loading from a constant address. | ||
| if (canBeRepresentedAsSls(*CN)) { | ||
| int32_t Imm = CN->getSExtValue(); | ||
| Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0)); | ||
| return true; | ||
| } | ||
| } | ||
| if (Addr.getOpcode() == ISD::OR && | ||
| Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) { | ||
| Offset = Addr.getOperand(1).getOperand(0); | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| bool LanaiDAGToDAGISel::selectAddrRiSpls(SDValue Addr, SDValue &Base, | ||
| SDValue &Offset, SDValue &AluOp, | ||
| bool RiMode) { | ||
| SDLoc DL(Addr); | ||
|
|
||
| if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) { | ||
| if (RiMode) { | ||
| // Fits in 16-bit signed immediate. | ||
| if (isInt<16>(CN->getSExtValue())) { | ||
| int16_t Imm = CN->getSExtValue(); | ||
| Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0)); | ||
| Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0)); | ||
| AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32); | ||
| return true; | ||
| } | ||
| // Allow SLS to match if the constant doesn't fit in 16 bits but can be | ||
| // represented as an SLS. | ||
| if (canBeRepresentedAsSls(*CN)) | ||
| return false; | ||
| } else { | ||
| // Fits in 10-bit signed immediate. | ||
| if (isInt<10>(CN->getSExtValue())) { | ||
| int16_t Imm = CN->getSExtValue(); | ||
| Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0)); | ||
| Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0)); | ||
| AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32); | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // if Address is FI, get the TargetFrameIndex. | ||
| if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { | ||
| Base = CurDAG->getTargetFrameIndex( | ||
| FIN->getIndex(), | ||
| getTargetLowering()->getPointerTy(CurDAG->getDataLayout())); | ||
| Offset = CurDAG->getTargetConstant(0, DL, MVT::i32); | ||
| AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32); | ||
| return true; | ||
| } | ||
|
|
||
| // Skip direct calls | ||
| if ((Addr.getOpcode() == ISD::TargetExternalSymbol || | ||
| Addr.getOpcode() == ISD::TargetGlobalAddress)) | ||
| return false; | ||
|
|
||
| // Address of the form imm + reg | ||
| ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode()); | ||
| if (AluOperator == ISD::ADD) { | ||
| AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32); | ||
| // Addresses of the form FI+const | ||
| if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) | ||
| if ((RiMode && isInt<16>(CN->getSExtValue())) || | ||
| (!RiMode && isInt<10>(CN->getSExtValue()))) { | ||
| // If the first operand is a FI, get the TargetFI Node | ||
| if (FrameIndexSDNode *FIN = | ||
| dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) { | ||
| Base = CurDAG->getTargetFrameIndex( | ||
| FIN->getIndex(), | ||
| getTargetLowering()->getPointerTy(CurDAG->getDataLayout())); | ||
| } else { | ||
| Base = Addr.getOperand(0); | ||
| } | ||
|
|
||
| Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i32); | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| // Let SLS match SMALL instead of RI. | ||
| if (AluOperator == ISD::OR && RiMode && | ||
| Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) | ||
| return false; | ||
|
|
||
| Base = Addr; | ||
| Offset = CurDAG->getTargetConstant(0, DL, MVT::i32); | ||
| AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32); | ||
| return true; | ||
| } | ||
|
|
||
| bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr, SDValue &Base, | ||
| SDValue &Offset, SDValue &AluOp) { | ||
| return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RImode=*/true); | ||
| } | ||
|
|
||
| bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr, SDValue &Base, | ||
| SDValue &Offset, SDValue &AluOp) { | ||
| return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/false); | ||
| } | ||
|
|
||
| bool LanaiDAGToDAGISel::selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2, | ||
| SDValue &AluOp) { | ||
| // if Address is FI, get the TargetFrameIndex. | ||
| if (Addr.getOpcode() == ISD::FrameIndex) | ||
| return false; | ||
|
|
||
| // Skip direct calls | ||
| if ((Addr.getOpcode() == ISD::TargetExternalSymbol || | ||
| Addr.getOpcode() == ISD::TargetGlobalAddress)) | ||
| return false; | ||
|
|
||
| // Address of the form OP + OP | ||
| ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode()); | ||
| LPAC::AluCode AluCode = LPAC::isdToLanaiAluCode(AluOperator); | ||
| if (AluCode != LPAC::UNKNOWN) { | ||
| // Skip addresses of the form FI OP const | ||
| if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) | ||
| if (isInt<16>(CN->getSExtValue())) | ||
| return false; | ||
|
|
||
| // Skip addresses with hi/lo operands | ||
| if (Addr.getOperand(0).getOpcode() == LanaiISD::HI || | ||
| Addr.getOperand(0).getOpcode() == LanaiISD::LO || | ||
| Addr.getOperand(0).getOpcode() == LanaiISD::SMALL || | ||
| Addr.getOperand(1).getOpcode() == LanaiISD::HI || | ||
| Addr.getOperand(1).getOpcode() == LanaiISD::LO || | ||
| Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) | ||
| return false; | ||
|
|
||
| // Addresses of the form register OP register | ||
| R1 = Addr.getOperand(0); | ||
| R2 = Addr.getOperand(1); | ||
| AluOp = CurDAG->getTargetConstant(AluCode, SDLoc(Addr), MVT::i32); | ||
| return true; | ||
| } | ||
|
|
||
| // Skip addresses with zero offset | ||
| return false; | ||
| } | ||
|
|
||
| bool LanaiDAGToDAGISel::SelectInlineAsmMemoryOperand( | ||
| const SDValue &Op, unsigned ConstraintCode, std::vector<SDValue> &OutOps) { | ||
| SDValue Op0, Op1, AluOp; | ||
| switch (ConstraintCode) { | ||
| default: | ||
| return true; | ||
| case InlineAsm::Constraint_m: // memory | ||
| if (!selectAddrRr(Op, Op0, Op1, AluOp) && | ||
| !selectAddrRi(Op, Op0, Op1, AluOp)) | ||
| return true; | ||
| break; | ||
| } | ||
|
|
||
| OutOps.push_back(Op0); | ||
| OutOps.push_back(Op1); | ||
| OutOps.push_back(AluOp); | ||
| return false; | ||
| } | ||
|
|
||
| // Select instructions not customized! Used for | ||
| // expanded, promoted and normal instructions | ||
| SDNode *LanaiDAGToDAGISel::Select(SDNode *Node) { | ||
| unsigned Opcode = Node->getOpcode(); | ||
|
|
||
| // 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. | ||
| SDNode *ResNode = nullptr; | ||
| switch (Opcode) { | ||
| case ISD::FrameIndex: | ||
| ResNode = selectFrameIndex(Node); | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
|
|
||
| // Select the default instruction | ||
| if (ResNode == nullptr) | ||
| ResNode = SelectCode(Node); | ||
|
|
||
| DEBUG(errs() << "=> "); | ||
| if (ResNode == NULL || ResNode == Node) | ||
| DEBUG(Node->dump(CurDAG)); | ||
| else | ||
| DEBUG(ResNode->dump(CurDAG)); | ||
| DEBUG(errs() << "\n"); | ||
| return ResNode; | ||
| } | ||
|
|
||
| SDNode *LanaiDAGToDAGISel::selectFrameIndex(SDNode *Node) { | ||
| SDLoc DL(Node); | ||
| SDValue Imm = CurDAG->getTargetConstant(0, DL, MVT::i32); | ||
| int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex(); | ||
| EVT VT = Node->getValueType(0); | ||
| SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); | ||
| unsigned Opc = Lanai::ADD_I_LO; | ||
| if (Node->hasOneUse()) | ||
| return CurDAG->SelectNodeTo(Node, Opc, VT, TFI, Imm); | ||
| return CurDAG->getMachineNode(Opc, DL, VT, TFI, Imm); | ||
| } | ||
|
|
||
| // createLanaiISelDag - This pass converts a legalized DAG into a | ||
| // Lanai-specific DAG, ready for instruction scheduling. | ||
| FunctionPass *llvm::createLanaiISelDag(LanaiTargetMachine &TM) { | ||
| return new LanaiDAGToDAGISel(TM); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| //===-- LanaiISelLowering.h - Lanai 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 Lanai uses to lower LLVM code into a | ||
| // selection DAG. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_LANAI_LANAIISELLOWERING_H | ||
| #define LLVM_LIB_TARGET_LANAI_LANAIISELLOWERING_H | ||
|
|
||
| #include "Lanai.h" | ||
| #include "LanaiRegisterInfo.h" | ||
| #include "llvm/CodeGen/SelectionDAG.h" | ||
| #include "llvm/Target/TargetLowering.h" | ||
|
|
||
| namespace llvm { | ||
| namespace LanaiISD { | ||
| enum { | ||
| FIRST_NUMBER = ISD::BUILTIN_OP_END, | ||
|
|
||
| ADJDYNALLOC, | ||
|
|
||
| // Return with a flag operand. Operand 0 is the chain operand. | ||
| RET_FLAG, | ||
|
|
||
| // CALL - These operations represent an abstract call instruction, which | ||
| // includes a bunch of information. | ||
| CALL, | ||
|
|
||
| // SELECT_CC - Operand 0 and operand 1 are selection variable, operand 3 | ||
| // is condition code and operand 4 is flag operand. | ||
| SELECT_CC, | ||
|
|
||
| // SETCC - Store the conditional to a register | ||
| SETCC, | ||
|
|
||
| // SET_FLAG - Set flag compare | ||
| SET_FLAG, | ||
|
|
||
| // BR_CC - Used to glue together a conditional branch and comparison | ||
| BR_CC, | ||
|
|
||
| // Wrapper - A wrapper node for TargetConstantPool, TargetExternalSymbol, | ||
| // and TargetGlobalAddress. | ||
| Wrapper, | ||
|
|
||
| // Get the Higher/Lower 16 bits from a 32-bit immediate | ||
| HI, | ||
| LO, | ||
|
|
||
| // Small 21-bit immediate in global memory | ||
| SMALL | ||
| }; | ||
| } // namespace LanaiISD | ||
|
|
||
| class LanaiSubtarget; | ||
|
|
||
| class LanaiTargetLowering : public TargetLowering { | ||
| public: | ||
| LanaiTargetLowering(const TargetMachine &TM, const LanaiSubtarget &STI); | ||
|
|
||
| // LowerOperation - Provide custom lowering hooks for some operations. | ||
| SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; | ||
|
|
||
| // getTargetNodeName - This method returns the name of a target specific | ||
| // DAG node. | ||
| const char *getTargetNodeName(unsigned Opcode) const override; | ||
|
|
||
| SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerCTTZ(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerCTLZ(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerCTTZ_ZERO_UNDEF(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const; | ||
| SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; | ||
|
|
||
| unsigned getRegisterByName(const char *RegName, EVT VT, | ||
| SelectionDAG &DAG) const override; | ||
| std::pair<unsigned, const TargetRegisterClass *> | ||
| getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, | ||
| StringRef Constraint, MVT VT) const override; | ||
| ConstraintWeight | ||
| getSingleConstraintMatchWeight(AsmOperandInfo &Info, | ||
| const char *Constraint) const override; | ||
| void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, | ||
| std::vector<SDValue> &Ops, | ||
| SelectionDAG &DAG) const override; | ||
|
|
||
| private: | ||
| SDValue LowerCCCCallTo(SDValue Chain, SDValue Callee, | ||
| CallingConv::ID CallConv, bool IsVarArg, | ||
| bool IsTailCall, | ||
| const SmallVectorImpl<ISD::OutputArg> &Outs, | ||
| const SmallVectorImpl<SDValue> &OutVals, | ||
| const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl, | ||
| SelectionDAG &DAG, | ||
| SmallVectorImpl<SDValue> &InVals) const; | ||
|
|
||
| SDValue LowerCCCArguments(SDValue Chain, CallingConv::ID CallConv, | ||
| bool IsVarArg, | ||
| const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, | ||
| SelectionDAG &DAG, | ||
| SmallVectorImpl<SDValue> &InVals) const; | ||
|
|
||
| SDValue LowerCallResult(SDValue Chain, SDValue InFlag, | ||
| CallingConv::ID CallConv, bool IsVarArg, | ||
| const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, | ||
| SelectionDAG &DAG, | ||
| SmallVectorImpl<SDValue> &InVals) const; | ||
|
|
||
| SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, | ||
| SmallVectorImpl<SDValue> &InVals) const override; | ||
|
|
||
| SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, | ||
| bool IsVarArg, | ||
| const SmallVectorImpl<ISD::InputArg> &Ins, | ||
| SDLoc DL, SelectionDAG &DAG, | ||
| SmallVectorImpl<SDValue> &InVals) const override; | ||
|
|
||
| SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, | ||
| const SmallVectorImpl<ISD::OutputArg> &Outs, | ||
| const SmallVectorImpl<SDValue> &OutVals, SDLoc DL, | ||
| SelectionDAG &DAG) const override; | ||
|
|
||
| const LanaiRegisterInfo *TRI; | ||
| }; | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_LANAI_LANAIISELLOWERING_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,324 @@ | ||
| //===-- LanaiInstrInfo.cpp - Lanai 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 Lanai implementation of the TargetInstrInfo class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "Lanai.h" | ||
| #include "LanaiInstrInfo.h" | ||
| #include "LanaiMachineFunctionInfo.h" | ||
| #include "LanaiTargetMachine.h" | ||
| #include "llvm/ADT/STLExtras.h" | ||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "llvm/CodeGen/MachineFunctionPass.h" | ||
| #include "llvm/CodeGen/MachineInstrBuilder.h" | ||
| #include "llvm/CodeGen/MachineRegisterInfo.h" | ||
| #include "llvm/Support/ErrorHandling.h" | ||
| #include "llvm/Support/TargetRegistry.h" | ||
|
|
||
| #define GET_INSTRINFO_CTOR_DTOR | ||
| #include "LanaiGenInstrInfo.inc" | ||
|
|
||
| namespace llvm { | ||
| LanaiInstrInfo::LanaiInstrInfo() | ||
| : LanaiGenInstrInfo(Lanai::ADJCALLSTACKDOWN, Lanai::ADJCALLSTACKUP), | ||
| RegisterInfo() {} | ||
|
|
||
| void LanaiInstrInfo::copyPhysReg(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator Position, | ||
| DebugLoc DL, unsigned DestinationRegister, | ||
| unsigned SourceRegister, | ||
| bool KillSource) const { | ||
| if (!Lanai::GPRRegClass.contains(DestinationRegister, SourceRegister)) { | ||
| llvm_unreachable("Impossible reg-to-reg copy"); | ||
| } | ||
|
|
||
| BuildMI(MBB, Position, DL, get(Lanai::OR_I_LO), DestinationRegister) | ||
| .addReg(SourceRegister, getKillRegState(KillSource)) | ||
| .addImm(0); | ||
| } | ||
|
|
||
| void LanaiInstrInfo::storeRegToStackSlot( | ||
| MachineBasicBlock &MBB, MachineBasicBlock::iterator Position, | ||
| unsigned SourceRegister, bool IsKill, int FrameIndex, | ||
| const TargetRegisterClass *RegisterClass, | ||
| const TargetRegisterInfo *RegisterInfo) const { | ||
| DebugLoc DL; | ||
| if (Position != MBB.end()) { | ||
| DL = Position->getDebugLoc(); | ||
| } | ||
|
|
||
| if (!Lanai::GPRRegClass.hasSubClassEq(RegisterClass)) { | ||
| llvm_unreachable("Can't store this register to stack slot"); | ||
| } | ||
| BuildMI(MBB, Position, DL, get(Lanai::SW_RI)) | ||
| .addReg(SourceRegister, getKillRegState(IsKill)) | ||
| .addFrameIndex(FrameIndex) | ||
| .addImm(0) | ||
| .addImm(LPAC::ADD); | ||
| } | ||
|
|
||
| void LanaiInstrInfo::loadRegFromStackSlot( | ||
| MachineBasicBlock &MBB, MachineBasicBlock::iterator Position, | ||
| unsigned DestinationRegister, int FrameIndex, | ||
| const TargetRegisterClass *RegisterClass, | ||
| const TargetRegisterInfo *RegisterInfo) const { | ||
| DebugLoc DL; | ||
| if (Position != MBB.end()) { | ||
| DL = Position->getDebugLoc(); | ||
| } | ||
|
|
||
| if (!Lanai::GPRRegClass.hasSubClassEq(RegisterClass)) { | ||
| llvm_unreachable("Can't load this register from stack slot"); | ||
| } | ||
| BuildMI(MBB, Position, DL, get(Lanai::LDW_RI), DestinationRegister) | ||
| .addFrameIndex(FrameIndex) | ||
| .addImm(0) | ||
| .addImm(LPAC::ADD); | ||
| } | ||
|
|
||
| bool LanaiInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { | ||
| return false; | ||
| } | ||
|
|
||
| static LPCC::CondCode GetOppositeBranchCondition(LPCC::CondCode CC) { | ||
| switch (CC) { | ||
| case LPCC::ICC_T: // true | ||
| return LPCC::ICC_F; | ||
| case LPCC::ICC_F: // false | ||
| return LPCC::ICC_T; | ||
| case LPCC::ICC_HI: // high | ||
| return LPCC::ICC_LS; | ||
| case LPCC::ICC_LS: // low or same | ||
| return LPCC::ICC_HI; | ||
| case LPCC::ICC_CC: // carry cleared | ||
| return LPCC::ICC_CS; | ||
| case LPCC::ICC_CS: // carry set | ||
| return LPCC::ICC_CC; | ||
| case LPCC::ICC_NE: // not equal | ||
| return LPCC::ICC_EQ; | ||
| case LPCC::ICC_EQ: // equal | ||
| return LPCC::ICC_NE; | ||
| case LPCC::ICC_VC: // oVerflow cleared | ||
| return LPCC::ICC_VS; | ||
| case LPCC::ICC_VS: // oVerflow set | ||
| return LPCC::ICC_VC; | ||
| case LPCC::ICC_PL: // plus (note: 0 is "minus" too here) | ||
| return LPCC::ICC_MI; | ||
| case LPCC::ICC_MI: // minus | ||
| return LPCC::ICC_PL; | ||
| case LPCC::ICC_GE: // greater than or equal | ||
| return LPCC::ICC_LT; | ||
| case LPCC::ICC_LT: // less than | ||
| return LPCC::ICC_GE; | ||
| case LPCC::ICC_GT: // greater than | ||
| return LPCC::ICC_LE; | ||
| case LPCC::ICC_LE: // less than or equal | ||
| return LPCC::ICC_GT; | ||
| default: | ||
| llvm_unreachable("Invalid condtional code"); | ||
| } | ||
| } | ||
|
|
||
| // The AnalyzeBranch function is used to examine conditional instructions and | ||
| // remove unnecessary instructions. This method is used by BranchFolder and | ||
| // IfConverter machine function passes to improve the CFG. | ||
| // - TrueBlock is set to the destination if condition evaluates true (it is the | ||
| // nullptr if the destination is the fall-through branch); | ||
| // - FalseBlock is set to the destination if condition evaluates to false (it | ||
| // is the nullptr if the branch is unconditional); | ||
| // - condition is populated with machine operands needed to generate the branch | ||
| // to insert in InsertBranch; | ||
| // Returns: false if branch could successfully be analyzed. | ||
| bool LanaiInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, | ||
| MachineBasicBlock *&TrueBlock, | ||
| MachineBasicBlock *&FalseBlock, | ||
| SmallVectorImpl<MachineOperand> &Condition, | ||
| bool AllowModify) const { | ||
| // Iterator to current instruction being considered. | ||
| MachineBasicBlock::iterator Instruction = MBB.end(); | ||
|
|
||
| // Start from the bottom of the block and work up, examining the | ||
| // terminator instructions. | ||
| while (Instruction != MBB.begin()) { | ||
| --Instruction; | ||
|
|
||
| // Skip over debug values. | ||
| if (Instruction->isDebugValue()) | ||
| continue; | ||
|
|
||
| // Working from the bottom, when we see a non-terminator | ||
| // instruction, we're done. | ||
| if (!isUnpredicatedTerminator(*Instruction)) | ||
| break; | ||
|
|
||
| // A terminator that isn't a branch can't easily be handled | ||
| // by this analysis. | ||
| if (!Instruction->isBranch()) | ||
| return true; | ||
|
|
||
| // Handle unconditional branches. | ||
| if (Instruction->getOpcode() == Lanai::BT) { | ||
| if (!AllowModify) { | ||
| TrueBlock = Instruction->getOperand(0).getMBB(); | ||
| continue; | ||
| } | ||
|
|
||
| // If the block has any instructions after a branch, delete them. | ||
| while (std::next(Instruction) != MBB.end()) { | ||
| std::next(Instruction)->eraseFromParent(); | ||
| } | ||
|
|
||
| Condition.clear(); | ||
| FalseBlock = nullptr; | ||
|
|
||
| // Delete the jump if it's equivalent to a fall-through. | ||
| if (MBB.isLayoutSuccessor(Instruction->getOperand(0).getMBB())) { | ||
| TrueBlock = nullptr; | ||
| Instruction->eraseFromParent(); | ||
| Instruction = MBB.end(); | ||
| continue; | ||
| } | ||
|
|
||
| // TrueBlock is used to indicate the unconditional destination. | ||
| TrueBlock = Instruction->getOperand(0).getMBB(); | ||
| continue; | ||
| } | ||
|
|
||
| // Handle conditional branches | ||
| unsigned Opcode = Instruction->getOpcode(); | ||
| if (Opcode != Lanai::BRCC) | ||
| return true; // Unknown opcode. | ||
|
|
||
| // Multiple conditional branches are not handled here so only proceed if | ||
| // there are no conditions enqueued. | ||
| if (Condition.empty()) { | ||
| LPCC::CondCode BranchCond = | ||
| static_cast<LPCC::CondCode>(Instruction->getOperand(1).getImm()); | ||
|
|
||
| // TrueBlock is the target of the previously seen unconditional branch. | ||
| FalseBlock = TrueBlock; | ||
| TrueBlock = Instruction->getOperand(0).getMBB(); | ||
| Condition.push_back(MachineOperand::CreateImm(BranchCond)); | ||
| continue; | ||
| } | ||
|
|
||
| // Multiple conditional branches are not handled. | ||
| return true; | ||
| } | ||
|
|
||
| // Return false indicating branch successfully analyzed. | ||
| return false; | ||
| } | ||
|
|
||
| // ReverseBranchCondition - Reverses the branch condition of the specified | ||
| // condition list, returning false on success and true if it cannot be | ||
| // reversed. | ||
| bool LanaiInstrInfo::ReverseBranchCondition( | ||
| SmallVectorImpl<llvm::MachineOperand> &Condition) const { | ||
| assert((Condition.size() == 1) && | ||
| "Lanai branch conditions should have one component."); | ||
|
|
||
| LPCC::CondCode BranchCond = | ||
| static_cast<LPCC::CondCode>(Condition[0].getImm()); | ||
| Condition[0].setImm(GetOppositeBranchCondition(BranchCond)); | ||
| return false; | ||
| } | ||
|
|
||
| // Insert the branch with condition specified in condition and given targets | ||
| // (TrueBlock and FalseBlock). This function returns the number of machine | ||
| // instructions inserted. | ||
| unsigned LanaiInstrInfo::InsertBranch(MachineBasicBlock &MBB, | ||
| MachineBasicBlock *TrueBlock, | ||
| MachineBasicBlock *FalseBlock, | ||
| ArrayRef<MachineOperand> Condition, | ||
| DebugLoc DL) const { | ||
| // Shouldn't be a fall through. | ||
| assert(TrueBlock && "InsertBranch must not be told to insert a fallthrough"); | ||
|
|
||
| // If condition is empty then an unconditional branch is being inserted. | ||
| if (Condition.empty()) { | ||
| assert(!FalseBlock && "Unconditional branch with multiple successors!"); | ||
| BuildMI(&MBB, DL, get(Lanai::BT)).addMBB(TrueBlock); | ||
| return 1; | ||
| } | ||
|
|
||
| // Else a conditional branch is inserted. | ||
| assert((Condition.size() == 1) && | ||
| "Lanai branch conditions should have one component."); | ||
| unsigned ConditionalCode = Condition[0].getImm(); | ||
| BuildMI(&MBB, DL, get(Lanai::BRCC)).addMBB(TrueBlock).addImm(ConditionalCode); | ||
|
|
||
| // If no false block, then false behavior is fall through and no branch needs | ||
| // to be inserted. | ||
| if (!FalseBlock) | ||
| return 1; | ||
|
|
||
| BuildMI(&MBB, DL, get(Lanai::BT)).addMBB(FalseBlock); | ||
| return 2; | ||
| } | ||
|
|
||
| unsigned LanaiInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { | ||
| MachineBasicBlock::iterator Instruction = MBB.end(); | ||
| unsigned Count = 0; | ||
|
|
||
| while (Instruction != MBB.begin()) { | ||
| --Instruction; | ||
| if (Instruction->isDebugValue()) | ||
| continue; | ||
| if (Instruction->getOpcode() != Lanai::BT && | ||
| Instruction->getOpcode() != Lanai::BRCC) { | ||
| break; | ||
| } | ||
|
|
||
| // Remove the branch. | ||
| Instruction->eraseFromParent(); | ||
| Instruction = MBB.end(); | ||
| ++Count; | ||
| } | ||
|
|
||
| return Count; | ||
| } | ||
|
|
||
| unsigned LanaiInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, | ||
| int &FrameIndex) const { | ||
| if (MI->getOpcode() == Lanai::LDW_RI) | ||
| if (MI->getOperand(1).isFI() && MI->getOperand(2).isImm() && | ||
| MI->getOperand(2).getImm() == 0) { | ||
| FrameIndex = MI->getOperand(1).getIndex(); | ||
| return MI->getOperand(0).getReg(); | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| unsigned LanaiInstrInfo::isLoadFromStackSlotPostFE(const MachineInstr *MI, | ||
| int &FrameIndex) const { | ||
| if (MI->getOpcode() == Lanai::LDW_RI) { | ||
| unsigned Reg; | ||
| if ((Reg = isLoadFromStackSlot(MI, FrameIndex))) | ||
| return Reg; | ||
| // Check for post-frame index elimination operations | ||
| const MachineMemOperand *Dummy; | ||
| return hasLoadFromStackSlot(MI, Dummy, FrameIndex); | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| unsigned LanaiInstrInfo::isStoreToStackSlot(const MachineInstr *MI, | ||
| int &FrameIndex) const { | ||
| if (MI->getOpcode() == Lanai::SW_RI) | ||
| if (MI->getOperand(0).isFI() && MI->getOperand(1).isImm() && | ||
| MI->getOperand(1).getImm() == 0) { | ||
| FrameIndex = MI->getOperand(0).getIndex(); | ||
| return MI->getOperand(2).getReg(); | ||
| } | ||
| return 0; | ||
| } | ||
| } // namespace llvm |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| //===- LanaiInstrInfo.h - Lanai 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 Lanai implementation of the TargetInstrInfo class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_LANAI_LANAIINSTRINFO_H | ||
| #define LLVM_LIB_TARGET_LANAI_LANAIINSTRINFO_H | ||
|
|
||
| #include "LanaiRegisterInfo.h" | ||
| #include "llvm/Target/TargetInstrInfo.h" | ||
|
|
||
| #define GET_INSTRINFO_HEADER | ||
| #include "LanaiGenInstrInfo.inc" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class LanaiInstrInfo : public LanaiGenInstrInfo { | ||
| const LanaiRegisterInfo RegisterInfo; | ||
|
|
||
| public: | ||
| LanaiInstrInfo(); | ||
|
|
||
| // getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As | ||
| // such, whenever a client has an instance of instruction info, it should | ||
| // always be able to get register info as well (through this method). | ||
| virtual const LanaiRegisterInfo &getRegisterInfo() const { | ||
| return RegisterInfo; | ||
| } | ||
|
|
||
| unsigned isLoadFromStackSlot(const MachineInstr *MI, | ||
| int &FrameIndex) const override; | ||
|
|
||
| unsigned isLoadFromStackSlotPostFE(const MachineInstr *MI, | ||
| int &FrameIndex) const override; | ||
|
|
||
| unsigned isStoreToStackSlot(const MachineInstr *MI, | ||
| int &FrameIndex) const override; | ||
|
|
||
| void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator Position, | ||
| DebugLoc DL, unsigned DestinationRegister, | ||
| unsigned SourceRegister, bool KillSource) const override; | ||
|
|
||
| void | ||
| storeRegToStackSlot(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator Position, | ||
| unsigned SourceRegister, bool IsKill, int FrameIndex, | ||
| const TargetRegisterClass *RegisterClass, | ||
| const TargetRegisterInfo *RegisterInfo) const override; | ||
|
|
||
| void | ||
| loadRegFromStackSlot(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator Position, | ||
| unsigned DestinationRegister, int FrameIndex, | ||
| const TargetRegisterClass *RegisterClass, | ||
| const TargetRegisterInfo *RegisterInfo) const override; | ||
|
|
||
| bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const override; | ||
|
|
||
| bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TrueBlock, | ||
| MachineBasicBlock *&FalseBlock, | ||
| SmallVectorImpl<MachineOperand> &Condition, | ||
| bool AllowModify) const override; | ||
|
|
||
| unsigned RemoveBranch(MachineBasicBlock &MBB) const override; | ||
|
|
||
| bool ReverseBranchCondition( | ||
| SmallVectorImpl<MachineOperand> &Condition) const override; | ||
|
|
||
| unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TrueBlock, | ||
| MachineBasicBlock *FalseBlock, | ||
| ArrayRef<MachineOperand> Condition, | ||
| DebugLoc DL) const override; | ||
| }; | ||
|
|
||
| static inline bool isSPLSOpcode(unsigned Opcode) { | ||
| switch (Opcode) { | ||
| case Lanai::LDBs_RI: | ||
| case Lanai::LDBz_RI: | ||
| case Lanai::LDHs_RI: | ||
| case Lanai::LDHz_RI: | ||
| case Lanai::STB_RI: | ||
| case Lanai::STH_RI: | ||
| return true; | ||
| default: | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| static inline bool isRMOpcode(unsigned Opcode) { | ||
| switch (Opcode) { | ||
| case Lanai::LDW_RI: | ||
| case Lanai::SW_RI: | ||
| return true; | ||
| default: | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| static inline bool isRRMOpcode(unsigned Opcode) { | ||
| switch (Opcode) { | ||
| case Lanai::LDBs_RR: | ||
| case Lanai::LDBz_RR: | ||
| case Lanai::LDHs_RR: | ||
| case Lanai::LDHz_RR: | ||
| case Lanai::LDWz_RR: | ||
| case Lanai::LDW_RR: | ||
| case Lanai::STB_RR: | ||
| case Lanai::STH_RR: | ||
| case Lanai::SW_RR: | ||
| return true; | ||
| default: | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_LANAI_LANAIINSTRINFO_H |