Index: CODE_OWNERS.TXT =================================================================== --- CODE_OWNERS.TXT +++ CODE_OWNERS.TXT @@ -138,6 +138,10 @@ E: kparzysz@codeaurora.org D: Hexagon Backend +N: Jacques Pienaar +E: jpienaar@google.com +D: Lanai Backend + N: Paul Robinson E: paul_robinson@playstation.sony.com D: Sony PlayStation®4 support Index: lib/ObjectYAML/ELFYAML.cpp =================================================================== --- lib/ObjectYAML/ELFYAML.cpp +++ lib/ObjectYAML/ELFYAML.cpp @@ -194,6 +194,7 @@ ECase(EM_78KOR) ECase(EM_56800EX) ECase(EM_AMDGPU) + ECase(EM_LANAI) #undef ECase } @@ -526,6 +527,9 @@ case ELF::EM_ARM: #include "llvm/Support/ELFRelocs/ARM.def" break; + case ELF::EM_LANAI: +#include "llvm/Support/ELFRelocs/Lanai.def" + break; default: llvm_unreachable("Unsupported architecture"); } Index: lib/Target/LLVMBuild.txt =================================================================== --- lib/Target/LLVMBuild.txt +++ lib/Target/LLVMBuild.txt @@ -25,6 +25,7 @@ AVR BPF CppBackend + Lanai Hexagon MSP430 NVPTX Index: lib/Target/Lanai/AsmParser/CMakeLists.txt =================================================================== --- lib/Target/Lanai/AsmParser/CMakeLists.txt +++ lib/Target/Lanai/AsmParser/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMLanaiAsmParser + LanaiAsmParser.cpp + ) + +add_dependencies( LLVMLanaiAsmParser LanaiCommonTableGen ) Index: lib/Target/Lanai/AsmParser/LLVMBuild.txt =================================================================== --- lib/Target/Lanai/AsmParser/LLVMBuild.txt +++ lib/Target/Lanai/AsmParser/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/Lanai/AsmParser/LLVMBuild.txt ----------------*- Conf -*-===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = LanaiAsmParser +parent = Lanai +required_libraries = MC MCParser Support LanaiMCTargetDesc LanaiInfo +add_to_library_groups = Lanai Index: lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp =================================================================== --- lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp +++ lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp @@ -0,0 +1,1173 @@ +//===-- LanaiAsmParser.cpp - Parse Lanai assembly to MCInst instructions --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Lanai.h" +#include "MCTargetDesc/LanaiMCExpr.h" +#include "MCTargetDesc/LanaiMCTargetDesc.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/TargetRegistry.h" + +namespace llvm { +namespace { +struct LanaiOperand; + +class LanaiAsmParser : public MCTargetAsmParser { + // Parse operands + std::unique_ptr parseRegister(); + + std::unique_ptr parseImmediate(); + + std::unique_ptr parseIdentifier(); + + unsigned parseAluOperator(bool PreOp, bool PostOp); + + // Split the mnemonic stripping conditional code and quantifiers + StringRef splitMnemonic(StringRef Name, SMLoc NameLoc, + OperandVector *Operands); + + bool parsePrePost(StringRef Type, int *OffsetValue); + + bool ParseDirective(AsmToken DirectiveID) override; + + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + + bool ParseRegister(unsigned &RegNum, SMLoc &StartLoc, SMLoc &EndLoc) override; + + bool MatchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) override; + +// Auto-generated instruction matching functions +#define GET_ASSEMBLER_HEADER +#include "LanaiGenAsmMatcher.inc" + + OperandMatchResultTy parseOperand(OperandVector *Operands, + StringRef Mnemonic); + + OperandMatchResultTy parseMemoryOperand(OperandVector &Operands); + +public: + LanaiAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(Options, STI), Parser(Parser), + Lexer(Parser.getLexer()), SubtargetInfo(STI) { + setAvailableFeatures( + ComputeAvailableFeatures(SubtargetInfo.getFeatureBits())); + } + +private: + MCAsmParser &Parser; + MCAsmLexer &Lexer; + + const MCSubtargetInfo &SubtargetInfo; +}; + +// Auto-generated by TableGen +static unsigned MatchRegisterName(llvm::StringRef Name); + +// LanaiOperand - Instances of this class represented a parsed machine +// instruction +struct LanaiOperand : public MCParsedAsmOperand { + enum KindTy { + TOKEN, + REGISTER, + IMMEDIATE, + MEMORY_IMM, + MEMORY_REG_IMM, + MEMORY_REG_REG, + } Kind; + + SMLoc StartLoc, EndLoc; + + struct Token { + const char *Data; + unsigned Length; + }; + + struct RegOp { + unsigned RegNum; + }; + + struct ImmOp { + const MCExpr *Value; + }; + + struct MemOp { + unsigned BaseReg; + unsigned OffsetReg; + unsigned AluOp; + const MCExpr *Offset; + }; + + union { + struct Token Tok; + struct RegOp Reg; + struct ImmOp Imm; + struct MemOp Mem; + }; + + explicit LanaiOperand(KindTy Kind) : MCParsedAsmOperand(), Kind(Kind) {} + +public: + // The functions below are used by the autogenerated ASM matcher and hence to + // be of the form expected. + + // getStartLoc - Gets location of the first token of this operand + SMLoc getStartLoc() const override { return StartLoc; } + + // getEndLoc - Gets location of the last token of this operand + SMLoc getEndLoc() const override { return EndLoc; } + + unsigned getReg() const override { + assert(isReg() && "Invalid type access!"); + return Reg.RegNum; + } + + const MCExpr *getImm() const { + assert(isImm() && "Invalid type access!"); + return Imm.Value; + } + + StringRef getToken() const { + assert(isToken() && "Invalid type access!"); + return StringRef(Tok.Data, Tok.Length); + } + + unsigned getMemBaseReg() const { + assert(isMem() && "Invalid type access!"); + return Mem.BaseReg; + } + + unsigned getMemOffsetReg() const { + assert(isMem() && "Invalid type access!"); + return Mem.OffsetReg; + } + + const MCExpr *getMemOffset() const { + assert(isMem() && "Invalid type access!"); + return Mem.Offset; + } + + unsigned getMemOp() const { + assert(isMem() && "Invalid type access!"); + return Mem.AluOp; + } + + // Functions for testing operand type + bool isReg() const override { return Kind == REGISTER; } + + bool isImm() const override { return Kind == IMMEDIATE; } + + bool isMem() const override { + return isMemImm() || isMemRegImm() || isMemRegReg(); + } + + bool isMemImm() const { return Kind == MEMORY_IMM; } + + bool isMemRegImm() const { return Kind == MEMORY_REG_IMM; } + + bool isMemRegReg() const { return Kind == MEMORY_REG_REG; } + + bool isMemSpls() const { return isMemRegImm() || isMemRegReg(); } + + bool isToken() const override { return Kind == TOKEN; } + + bool isBrTarget() { return isImm() || isToken(); } + + bool isCallTarget() { return isImm() || isToken(); } + + bool isHiImm16() { + if (!isImm()) + return false; + + // Constant case + if (const MCConstantExpr *ConstExpr = dyn_cast(Imm.Value)) { + int64_t Value = ConstExpr->getValue(); + return Value != 0 && isShiftedUInt<16, 16>(Value); + } + + // Symbolic reference expression + if (const LanaiMCExpr *SymbolRefExpr = dyn_cast(Imm.Value)) + return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI; + + // Binary expression + if (const MCBinaryExpr *BinaryExpr = dyn_cast(Imm.Value)) + if (const LanaiMCExpr *SymbolRefExpr = + dyn_cast(BinaryExpr->getLHS())) + return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI; + + return false; + } + + bool isHiImm16And() { + if (!isImm()) + return false; + + const MCConstantExpr *ConstExpr = dyn_cast(Imm.Value); + if (ConstExpr) { + int64_t Value = ConstExpr->getValue(); + // Check if in the form 0xXYZWffff + return (Value != 0) && ((Value & ~0xffff0000) == 0xffff); + } + return false; + } + + bool isLoImm16() { + if (!isImm()) + return false; + + // Constant case + if (const MCConstantExpr *ConstExpr = dyn_cast(Imm.Value)) { + int64_t Value = ConstExpr->getValue(); + // Check if value fits in 16 bits + return isUInt<16>(static_cast(Value)); + } + + // Symbolic reference expression + if (const LanaiMCExpr *SymbolRefExpr = dyn_cast(Imm.Value)) { + return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO; + } + + // Binary expression + if (const MCBinaryExpr *BinaryExpr = dyn_cast(Imm.Value)) { + if (const LanaiMCExpr *SymbolRefExpr = + dyn_cast(BinaryExpr->getLHS())) { + return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO; + } + } + + return false; + } + + bool isLoImm16Signed() { + if (!isImm()) + return false; + + // Constant case + if (const MCConstantExpr *ConstExpr = dyn_cast(Imm.Value)) { + int64_t Value = ConstExpr->getValue(); + // Check if value fits in 16 bits or value of the form 0xffffxyzw + return isInt<16>(static_cast(Value)); + } + + // Symbolic reference expression + if (const LanaiMCExpr *SymbolRefExpr = dyn_cast(Imm.Value)) + return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO; + + // Binary expression + if (const MCBinaryExpr *BinaryExpr = dyn_cast(Imm.Value)) { + if (const LanaiMCExpr *SymbolRefExpr = + dyn_cast(BinaryExpr->getLHS())) { + return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO; + } + } + + return false; + } + + bool isLoImm16And() { + if (!isImm()) + return false; + + const MCConstantExpr *ConstExpr = dyn_cast(Imm.Value); + if (ConstExpr) { + int64_t Value = ConstExpr->getValue(); + // Check if in the form 0xffffXYZW + return ((Value & ~0xffff) == 0xffff0000); + } + return false; + } + + bool isNegImm6() { + if (!isImm()) + return false; + + const MCConstantExpr *ConstExpr = dyn_cast(Imm.Value); + if (!ConstExpr) + return false; + int64_t Value = ConstExpr->getValue(); + return (Value < 0) && isInt<6>(Value); + } + + bool isImm6() { + if (!isImm()) + return false; + + const MCConstantExpr *ConstExpr = dyn_cast(Imm.Value); + if (!ConstExpr) + return false; + int64_t Value = ConstExpr->getValue(); + return (Value >= 0) && isInt<6>(Value); + } + + bool isLoImm21() { + if (!isImm()) + return false; + + // Constant case + if (const MCConstantExpr *ConstExpr = dyn_cast(Imm.Value)) { + int64_t Value = ConstExpr->getValue(); + return isUInt<21>(Value); + } + + // Symbolic reference expression + if (const LanaiMCExpr *SymbolRefExpr = dyn_cast(Imm.Value)) { + return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None; + } + if (const MCSymbolRefExpr *SymbolRefExpr = + dyn_cast(Imm.Value)) { + return SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None; + } + + // Binary expression + if (const MCBinaryExpr *BinaryExpr = dyn_cast(Imm.Value)) { + if (const LanaiMCExpr *SymbolRefExpr = + dyn_cast(BinaryExpr->getLHS())) { + return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None; + } + if (const MCSymbolRefExpr *SymbolRefExpr = + dyn_cast(BinaryExpr->getLHS())) { + return SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None; + } + } + + return false; + } + + bool isImm10() { + if (!isImm()) + return false; + + const MCConstantExpr *ConstExpr = dyn_cast(Imm.Value); + if (!ConstExpr) + return false; + int64_t Value = ConstExpr->getValue(); + return isInt<10>(Value); + } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + // Add as immediates where possible. Null MCExpr = 0 + if (Expr == 0) { + Inst.addOperand(MCOperand::createImm(0)); + } else if (const MCConstantExpr *ConstExpr = + dyn_cast(Expr)) { + Inst.addOperand( + MCOperand::createImm(static_cast(ConstExpr->getValue()))); + } else { + Inst.addOperand(MCOperand::createExpr(Expr)); + } + } + + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getReg())); + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + + void addBrTargetOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + + void addCallTargetOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + + void addMemImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCExpr *Expr = getMemOffset(); + addExpr(Inst, Expr); + } + + void addMemRegImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getMemBaseReg())); + const MCExpr *Expr = getMemOffset(); + addExpr(Inst, Expr); + Inst.addOperand(MCOperand::createImm(getMemOp())); + } + + void addMemRegRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getMemBaseReg())); + assert(getMemOffsetReg() != 0 && "Invalid offset"); + Inst.addOperand(MCOperand::createReg(getMemOffsetReg())); + Inst.addOperand(MCOperand::createImm(getMemOp())); + } + + void addMemSplsOperands(MCInst &Inst, unsigned N) const { + if (isMemRegImm()) + addMemRegImmOperands(Inst, N); + if (isMemRegReg()) + addMemRegRegOperands(Inst, N); + } + + void addImm6Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + + void addNegImm6Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *ConstExpr = dyn_cast(getImm()); + Inst.addOperand(MCOperand::createImm(-ConstExpr->getValue())); + } + + void addImm10Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + + void addLoImm16Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + if (const MCConstantExpr *ConstExpr = dyn_cast(getImm())) { + Inst.addOperand( + MCOperand::createImm(static_cast(ConstExpr->getValue()))); + } else if (isa(getImm())) { +#ifndef NDEBUG + const LanaiMCExpr *SymbolRefExpr = dyn_cast(getImm()); + assert(SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO); +#endif + Inst.addOperand(MCOperand::createExpr(getImm())); + } else if (isa(getImm())) { +#ifndef NDEBUG + const MCBinaryExpr *BinaryExpr = dyn_cast(getImm()); + assert(dyn_cast(BinaryExpr->getLHS()) && + dyn_cast(BinaryExpr->getLHS())->getKind() == + LanaiMCExpr::VK_Lanai_ABS_LO); +#endif + Inst.addOperand(MCOperand::createExpr(getImm())); + } else { + assert(false && "Operand type not supported."); + } + } + + void addLoImm16AndOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + if (const MCConstantExpr *ConstExpr = dyn_cast(getImm())) { + Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0xffff)); + } else { + assert(false && "Operand type not supported."); + } + } + + void addHiImm16Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + if (const MCConstantExpr *ConstExpr = dyn_cast(getImm())) { + Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16)); + } else if (isa(getImm())) { +#ifndef NDEBUG + const LanaiMCExpr *SymbolRefExpr = dyn_cast(getImm()); + assert(SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI); +#endif + Inst.addOperand(MCOperand::createExpr(getImm())); + } else if (isa(getImm())) { +#ifndef NDEBUG + const MCBinaryExpr *BinaryExpr = dyn_cast(getImm()); + assert(dyn_cast(BinaryExpr->getLHS()) && + dyn_cast(BinaryExpr->getLHS())->getKind() == + LanaiMCExpr::VK_Lanai_ABS_HI); +#endif + Inst.addOperand(MCOperand::createExpr(getImm())); + } else { + assert(false && "Operand type not supported."); + } + } + + void addHiImm16AndOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + if (const MCConstantExpr *ConstExpr = dyn_cast(getImm())) + Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16)); + else + assert(false && "Operand type not supported."); + } + + void addLoImm21Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + if (const MCConstantExpr *ConstExpr = dyn_cast(getImm())) { + Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0x1fffff)); + } else if (isa(getImm())) { +#ifndef NDEBUG + const LanaiMCExpr *SymbolRefExpr = dyn_cast(getImm()); + assert(SymbolRefExpr && + SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None); +#endif + Inst.addOperand(MCOperand::createExpr(getImm())); + } else if (isa(getImm())) { +#ifndef NDEBUG + const MCSymbolRefExpr *SymbolRefExpr = + dyn_cast(getImm()); + assert(SymbolRefExpr && + SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None); +#endif + Inst.addOperand(MCOperand::createExpr(getImm())); + } else if (isa(getImm())) { +#ifndef NDEBUG + const MCBinaryExpr *BinaryExpr = dyn_cast(getImm()); + const LanaiMCExpr *SymbolRefExpr = + dyn_cast(BinaryExpr->getLHS()); + assert(SymbolRefExpr && + SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None); +#endif + Inst.addOperand(MCOperand::createExpr(getImm())); + } else { + assert(false && "Operand type not supported."); + } + } + + void print(raw_ostream &OS) const override { + switch (Kind) { + case IMMEDIATE: + OS << "Imm: " << getImm() << "\n"; + break; + case TOKEN: + OS << "Token: " << getToken() << "\n"; + break; + case REGISTER: + OS << "Reg: %r" << getReg() << "\n"; + break; + case MEMORY_IMM: + OS << "MemImm: " << *getMemOffset() << "\n"; + break; + case MEMORY_REG_IMM: + OS << "MemRegImm: " << getMemBaseReg() << "+" << *getMemOffset() << "\n"; + break; + case MEMORY_REG_REG: + assert(getMemOffset() == nullptr); + OS << "MemRegReg: " << getMemBaseReg() << "+" + << "%r" << getMemOffsetReg() << "\n"; + break; + } + } + + static std::unique_ptr CreateToken(StringRef Str, SMLoc Start) { + auto Op = make_unique(TOKEN); + Op->Tok.Data = Str.data(); + Op->Tok.Length = Str.size(); + Op->StartLoc = Start; + Op->EndLoc = Start; + return Op; + } + + static std::unique_ptr createReg(unsigned RegNum, SMLoc Start, + SMLoc End) { + auto Op = make_unique(REGISTER); + Op->Reg.RegNum = RegNum; + Op->StartLoc = Start; + Op->EndLoc = End; + return Op; + } + + static std::unique_ptr createImm(const MCExpr *Value, + SMLoc Start, SMLoc End) { + auto Op = make_unique(IMMEDIATE); + Op->Imm.Value = Value; + Op->StartLoc = Start; + Op->EndLoc = End; + return Op; + } + + static std::unique_ptr + MorphToMemImm(std::unique_ptr Op) { + const MCExpr *Imm = Op->getImm(); + Op->Kind = MEMORY_IMM; + Op->Mem.BaseReg = 0; + Op->Mem.AluOp = LPAC::ADD; + Op->Mem.OffsetReg = 0; + Op->Mem.Offset = Imm; + return Op; + } + + static std::unique_ptr + MorphToMemRegReg(unsigned BaseReg, std::unique_ptr Op, + unsigned AluOp) { + unsigned OffsetReg = Op->getReg(); + Op->Kind = MEMORY_REG_REG; + Op->Mem.BaseReg = BaseReg; + Op->Mem.AluOp = AluOp; + Op->Mem.OffsetReg = OffsetReg; + Op->Mem.Offset = nullptr; + return Op; + } + + static std::unique_ptr + MorphToMemRegImm(unsigned BaseReg, std::unique_ptr Op, + unsigned AluOp) { + const MCExpr *Imm = Op->getImm(); + Op->Kind = MEMORY_REG_IMM; + Op->Mem.BaseReg = BaseReg; + Op->Mem.AluOp = AluOp; + Op->Mem.OffsetReg = 0; + Op->Mem.Offset = Imm; + return Op; + } +}; + +bool LanaiAsmParser::ParseDirective(AsmToken DirectiveId) { return true; } + +bool LanaiAsmParser::MatchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; + SMLoc ErrorLoc; + + switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) { + case Match_Success: + Out.EmitInstruction(Inst, SubtargetInfo); + return false; + case Match_MissingFeature: + return Error(IdLoc, "Instruction use requires option to be enabled"); + case Match_MnemonicFail: + return Error(IdLoc, "Unrecognized instruction mnemonic"); + case Match_InvalidOperand: { + ErrorLoc = IdLoc; + if (ErrorInfo != ~0U) { + if (ErrorInfo >= Operands.size()) + return Error(IdLoc, "Too few operands for instruction"); + + ErrorLoc = ((LanaiOperand &)*Operands[ErrorInfo]).getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IdLoc; + } + return Error(ErrorLoc, "Invalid operand for instruction"); + } + default: + break; + } + + llvm_unreachable("Unknown match type detected!"); +} + +// Both '%rN' and 'rN' are parsed as valid registers. This was done to remain +// backwards compatible with GCC and the different ways inline assembly is +// handled. +// TODO: see if there isn't a better way to do this. +std::unique_ptr LanaiAsmParser::parseRegister() { + SMLoc Start = Parser.getTok().getLoc(); + SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + unsigned RegNum; + // Eat the '%'. + if (Lexer.getKind() == AsmToken::Percent) + Parser.Lex(); + if (Lexer.getKind() == AsmToken::Identifier) { + RegNum = MatchRegisterName(Lexer.getTok().getIdentifier()); + if (RegNum == 0) + return 0; + Parser.Lex(); // Eat identifier token + return LanaiOperand::createReg(RegNum, Start, End); + } + return 0; +} + +bool LanaiAsmParser::ParseRegister(unsigned &RegNum, SMLoc &StartLoc, + SMLoc &EndLoc) { + std::unique_ptr Op = parseRegister(); + if (Op != 0) + RegNum = Op->getReg(); + return (Op == 0); +} + +std::unique_ptr LanaiAsmParser::parseIdentifier() { + SMLoc Start = Parser.getTok().getLoc(); + SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + const MCExpr *Res, *RHS = 0; + LanaiMCExpr::VariantKind Kind = LanaiMCExpr::VK_Lanai_None; + + if (Lexer.getKind() != AsmToken::Identifier) + return 0; + + StringRef Identifier; + if (Parser.parseIdentifier(Identifier)) + return 0; + + // Check if identifier has a modifier + if (Identifier.equals_lower("hi")) + Kind = LanaiMCExpr::VK_Lanai_ABS_HI; + else if (Identifier.equals_lower("lo")) + Kind = LanaiMCExpr::VK_Lanai_ABS_LO; + + // If the identifier corresponds to a variant then extract the real + // identifier. + if (Kind != LanaiMCExpr::VK_Lanai_None) { + if (Lexer.getKind() != AsmToken::LParen) { + Error(Lexer.getLoc(), "Expected '('"); + return 0; + } + Lexer.Lex(); // lex '(' + + // Parse identifier + if (Parser.parseIdentifier(Identifier)) + return 0; + } + + // If addition parse the RHS. + if (Lexer.getKind() == AsmToken::Plus && Parser.parseExpression(RHS)) + return 0; + + // For variants parse the final ')' + if (Kind != LanaiMCExpr::VK_Lanai_None) { + if (Lexer.getKind() != AsmToken::RParen) { + Error(Lexer.getLoc(), "Expected ')'"); + return 0; + } + Lexer.Lex(); // lex ')' + } + + End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); + const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext()); + Res = LanaiMCExpr::create(Kind, Expr, getContext()); + + // Nest if this was an addition + if (RHS) + Res = MCBinaryExpr::createAdd(Res, RHS, getContext()); + + return LanaiOperand::createImm(Res, Start, End); +} + +std::unique_ptr LanaiAsmParser::parseImmediate() { + SMLoc Start = Parser.getTok().getLoc(); + SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + const MCExpr *ExprVal; + switch (Lexer.getKind()) { + case AsmToken::Identifier: + return parseIdentifier(); + case AsmToken::Plus: + case AsmToken::Minus: + case AsmToken::Integer: + case AsmToken::Dot: + if (!Parser.parseExpression(ExprVal)) + return LanaiOperand::createImm(ExprVal, Start, End); + default: + return 0; + } +} + +unsigned AluWithPrePost(unsigned AluCode, bool PreOp, bool PostOp) { + if (PreOp) + return LPAC::makePreOp(AluCode); + if (PostOp) + return LPAC::makePostOp(AluCode); + return AluCode; +} + +unsigned LanaiAsmParser::parseAluOperator(bool PreOp, bool PostOp) { + StringRef IdString; + Parser.parseIdentifier(IdString); + unsigned AluCode = LPAC::stringToLanaiAluCode(IdString); + if (AluCode == LPAC::UNKNOWN) { + Error(Parser.getTok().getLoc(), "Can't parse ALU operator"); + return 0; + } + return AluCode; +} + +int SizeForSuffix(StringRef T) { + return StringSwitch(T).EndsWith(".h", 2).EndsWith(".b", 1).Default(4); +} + +bool LanaiAsmParser::parsePrePost(StringRef Type, int *OffsetValue) { + bool PreOrPost = false; + if (Lexer.getKind() == Lexer.peekTok(true).getKind()) { + PreOrPost = true; + if (Lexer.is(AsmToken::Minus)) + *OffsetValue = -SizeForSuffix(Type); + else if (Lexer.is(AsmToken::Plus)) + *OffsetValue = SizeForSuffix(Type); + else + return false; + + // Eat the '-' '-' or '+' '+' + Parser.Lex(); + Parser.Lex(); + } else if (Lexer.is(AsmToken::Star)) { + Parser.Lex(); // Eat the '*' + PreOrPost = true; + } + + return PreOrPost; +} + +bool shouldBeSls(const LanaiOperand &Op) { + // The instruction should be encoded as an SLS if the constant is word + // aligned and will fit in 21 bits + if (const MCConstantExpr *ConstExpr = dyn_cast(Op.getImm())) { + int64_t Value = ConstExpr->getValue(); + return (Value % 4 == 0) && (Value >= 0) && (Value <= 0x1fffff); + } + // The instruction should be encoded as an SLS if the operand is a symbolic + // reference with no variant. + if (const LanaiMCExpr *SymbolRefExpr = dyn_cast(Op.getImm())) { + return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None; + } + // The instruction should be encoded as an SLS if the operand is a binary + // expression with the left-hand side being a symbolic reference with no + // variant. + if (const MCBinaryExpr *BinaryExpr = dyn_cast(Op.getImm())) { + const LanaiMCExpr *LHSSymbolRefExpr = + dyn_cast(BinaryExpr->getLHS()); + return (LHSSymbolRefExpr && + LHSSymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None); + } + return false; +} + +// Matches memory operand. Returns true if error encountered. +LanaiAsmParser::OperandMatchResultTy +LanaiAsmParser::parseMemoryOperand(OperandVector &Operands) { + // Try to match a memory operand. + // The memory operands are of the form: + // (1) Register|Immediate|'' '[' '*'? Register '*'? ']' or + // ^ + // (2) '[' '*'? Register '*'? AluOperator Register ']' + // ^ + // (3) '[' '--'|'++' Register '--'|'++' ']' + // + // (4) '[' Immediate ']' (for SLS) + + // Store the type for use in parsing pre/post increment/decrement operators + StringRef Type; + if (Operands[0]->isToken()) + Type = static_cast(Operands[0].get())->getToken(); + + // Use 0 if no offset given + int OffsetValue = 0; + unsigned BaseReg = 0; + unsigned AluOp = LPAC::ADD; + bool PostOp = false, PreOp = false; + + // Try to parse the offset + std::unique_ptr Op = parseRegister(); + if (!Op) + Op = parseImmediate(); + + // Only continue if next token is '[' + if (Lexer.isNot(AsmToken::LBrac)) { + if (!Op) + return MatchOperand_NoMatch; + + // The start of this custom parsing overlaps with register/immediate so + // consider this as a successful match of an operand of that type as the + // token stream can't be rewound to allow them to match separately. + Operands.push_back(std::move(Op)); + return MatchOperand_Success; + } + + Parser.Lex(); // Eat the '['. + std::unique_ptr Offset = nullptr; + if (Op) + Offset.swap(Op); + + // Determine if a pre operation + PreOp = parsePrePost(Type, &OffsetValue); + + Op = parseRegister(); + if (!Op) { + if (!Offset) { + if ((Op = parseImmediate()) && Lexer.is(AsmToken::RBrac)) { + Parser.Lex(); // Eat the ']' + + // Memory address operations aligned to word boundary are encoded as + // SLS, the rest as RM. + if (shouldBeSls(*Op)) { + Operands.push_back(LanaiOperand::MorphToMemImm(std::move(Op))); + } else { + if (!Op->isLoImm16Signed()) { + Error(Parser.getTok().getLoc(), + "Memory address is not word " + "aligned and larger than class RM can handle"); + return MatchOperand_ParseFail; + } + Operands.push_back(LanaiOperand::MorphToMemRegImm( + Lanai::R0, std::move(Op), LPAC::ADD)); + } + return MatchOperand_Success; + } + } + + Error(Parser.getTok().getLoc(), + "Unknown operand, expected register or immediate"); + return MatchOperand_ParseFail; + } + BaseReg = Op->getReg(); + + // Determine if a post operation + if (!PreOp) + PostOp = parsePrePost(Type, &OffsetValue); + + // If ] match form (1) else match form (2) + if (Lexer.is(AsmToken::RBrac)) { + Parser.Lex(); // Eat the ']'. + if (!Offset) { + SMLoc Start = Parser.getTok().getLoc(); + SMLoc End = + SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + const MCConstantExpr *OffsetConstExpr = + MCConstantExpr::create(OffsetValue, getContext()); + Offset = LanaiOperand::createImm(OffsetConstExpr, Start, End); + } + } else { + if (Offset || OffsetValue != 0) { + Error(Parser.getTok().getLoc(), "Expected ']'"); + return MatchOperand_ParseFail; + } + + // Parse operator + AluOp = parseAluOperator(PreOp, PostOp); + + // Second form requires offset register + Offset = parseRegister(); + if (!BaseReg || Lexer.isNot(AsmToken::RBrac)) { + Error(Parser.getTok().getLoc(), "Expected ']'"); + return MatchOperand_ParseFail; + } + Parser.Lex(); // Eat the ']'. + } + + // First form has addition as operator. Add pre- or post-op indicator as + // needed. + AluOp = AluWithPrePost(AluOp, PreOp, PostOp); + + // Ensure immediate offset is not too large + if (Offset->isImm() && !Offset->isLoImm16Signed()) { + Error(Parser.getTok().getLoc(), + "Memory address is not word " + "aligned and larger than class RM can handle"); + return MatchOperand_ParseFail; + } + + Operands.push_back( + Offset->isImm() + ? LanaiOperand::MorphToMemRegImm(BaseReg, std::move(Offset), AluOp) + : LanaiOperand::MorphToMemRegReg(BaseReg, std::move(Offset), AluOp)); + + return MatchOperand_Success; +} + +// Looks at a token type and creates the relevant operand from this +// information, adding to operands. +// If operand was parsed, returns false, else true. +LanaiAsmParser::OperandMatchResultTy +LanaiAsmParser::parseOperand(OperandVector *Operands, StringRef Mnemonic) { + // Check if the current operand has a custom associated parser, if so, try to + // custom parse the operand, or fallback to the general approach. + OperandMatchResultTy Result = MatchOperandParserImpl(*Operands, Mnemonic); + + if (Result == MatchOperand_Success) + return Result; + if (Result == MatchOperand_ParseFail) { + Parser.eatToEndOfStatement(); + return Result; + } + + // Attempt to parse token as register + std::unique_ptr Op = parseRegister(); + + // Attempt to parse token as immediate + if (!Op) + Op = parseImmediate(); + + // If the token could not be parsed then fail + if (!Op) { + Error(Parser.getTok().getLoc(), "Unknown operand"); + Parser.eatToEndOfStatement(); + return MatchOperand_ParseFail; + } + + // Push back parsed operand into list of operands + Operands->push_back(std::move(Op)); + + return MatchOperand_Success; +} + +// Split the mnemonic into ASM operand, conditional code and instruction +// qualifier (half-word, byte). +StringRef LanaiAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc, + OperandVector *Operands) { + size_t Next = Name.find('.'); + + StringRef Mnemonic = Name; + + bool IsBRR = false; + if (Name.endswith(".r")) { + Mnemonic = Name.substr(0, Name.size() - 2); + IsBRR = true; + } + + // Match b?? and s?? (BR, BRR, and SCC instruction classes). + if (Mnemonic[0] == 'b' || + (Mnemonic[0] == 's' && !Mnemonic.startswith("sel") && + !Mnemonic.startswith("st"))) { + // Parse instructions with a conditional code. For example, 'bne' is + // converted into two operands 'b' and 'ne'. + LPCC::CondCode CondCode = + LPCC::suffixToLanaiCondCode(Mnemonic.substr(1, Next)); + if (CondCode != LPCC::UNKNOWN) { + Mnemonic = Mnemonic.slice(0, 1); + Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc)); + Operands->push_back(LanaiOperand::createImm( + MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc)); + if (IsBRR) { + Operands->push_back(LanaiOperand::CreateToken(".r", NameLoc)); + } + return Mnemonic; + } + } + + // Parse other instructions with condition codes (RR instructions). + // We ignore .f here and assume they are flag-setting operations, not + // conditional codes (except for select instructions where flag-setting + // variants are not yet implemented). + if (Mnemonic.startswith("sel") || + (!Mnemonic.endswith(".f") && !Mnemonic.startswith("st"))) { + LPCC::CondCode CondCode = LPCC::suffixToLanaiCondCode(Mnemonic); + if (CondCode != LPCC::UNKNOWN) { + size_t Next = Mnemonic.rfind('.', Name.size()); + Mnemonic = Mnemonic.substr(0, Next + 1); + Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc)); + Operands->push_back(LanaiOperand::createImm( + MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc)); + return Mnemonic; + } + } + + Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc)); + if (IsBRR) { + Operands->push_back(LanaiOperand::CreateToken(".r", NameLoc)); + } + + return Mnemonic; +} + +bool IsMemoryAssignmentError(const OperandVector &Operands) { + // Detects if a memory operation has an erroneous base register modification. + // Memory operations are detected by matching the types of operands. + // + // TODO: This test is focussed on one specific instance (ld/st). + // Extend it to handle more cases or be more robust. + bool Modifies = false; + + int Offset = 0; + + if (Operands.size() < 5) + return false; + else if (Operands[0]->isToken() && Operands[1]->isReg() && + Operands[2]->isImm() && Operands[3]->isImm() && Operands[4]->isReg()) + Offset = 0; + else if (Operands[0]->isToken() && Operands[1]->isToken() && + Operands[2]->isReg() && Operands[3]->isImm() && + Operands[4]->isImm() && Operands[5]->isReg()) + Offset = 1; + else + return false; + + int PossibleAluOpIdx = Offset + 3; + int PossibleBaseIdx = Offset + 1; + int PossibleDestIdx = Offset + 4; + if (LanaiOperand *PossibleAluOp = + static_cast(Operands[PossibleAluOpIdx].get())) { + if (PossibleAluOp->isImm()) { + if (const MCConstantExpr *ConstExpr = + dyn_cast(PossibleAluOp->getImm())) { + Modifies = LPAC::modifiesOp(ConstExpr->getValue()); + } + } + } + return Modifies && Operands[PossibleBaseIdx]->isReg() && + Operands[PossibleDestIdx]->isReg() && + Operands[PossibleBaseIdx]->getReg() == + Operands[PossibleDestIdx]->getReg(); +} + +bool LanaiAsmParser::ParseInstruction(ParseInstructionInfo &Info, + StringRef Name, SMLoc NameLoc, + OperandVector &Operands) { + // First operand is token for instruction + StringRef Mnemonic = splitMnemonic(Name, NameLoc, &Operands); + + // If there are no more operands, then finish + if (Lexer.is(AsmToken::EndOfStatement)) + return false; + + // Parse first operand + if (parseOperand(&Operands, Mnemonic) != MatchOperand_Success) + return true; + + // If it is a st instruction with one 1 operand then it is a "store true". + // Transform <"st"> to <"s">, + if (Lexer.is(AsmToken::EndOfStatement) && Name == "st" && + Operands.size() == 2) { + Operands.erase(Operands.begin(), Operands.begin() + 1); + Operands.insert(Operands.begin(), LanaiOperand::CreateToken("s", NameLoc)); + Operands.insert(Operands.begin() + 1, + LanaiOperand::createImm( + MCConstantExpr::create(LPCC::ICC_T, getContext()), + NameLoc, NameLoc)); + } + + // If the instruction is a bt instruction with 1 operand (in assembly) then it + // is an unconditional branch instruction and the first two elements of + // operands need to be merged. + if (Lexer.is(AsmToken::EndOfStatement) && Name.startswith("bt") && + Operands.size() == 3) { + Operands.erase(Operands.begin(), Operands.begin() + 2); + Operands.insert(Operands.begin(), LanaiOperand::CreateToken("bt", NameLoc)); + } + + // Parse until end of statement, consuming commas between operands + while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.is(AsmToken::Comma)) { + // Consume comma token + Lexer.Lex(); + + // Parse next operand + if (parseOperand(&Operands, Mnemonic) != MatchOperand_Success) + return true; + } + + if (IsMemoryAssignmentError(Operands)) { + Error(Parser.getTok().getLoc(), + "the destination register can't equal the base register in an " + "instruction that modifies the base register."); + return true; + } + + return false; +} + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "LanaiGenAsmMatcher.inc" +} // namespace + +extern "C" void LLVMInitializeLanaiAsmParser() { + RegisterMCAsmParser x(TheLanaiTarget); +} + +} // namespace llvm Index: lib/Target/Lanai/CMakeLists.txt =================================================================== --- lib/Target/Lanai/CMakeLists.txt +++ lib/Target/Lanai/CMakeLists.txt @@ -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) Index: lib/Target/Lanai/Disassembler/CMakeLists.txt =================================================================== --- lib/Target/Lanai/Disassembler/CMakeLists.txt +++ lib/Target/Lanai/Disassembler/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMLanaiDisassembler + LanaiDisassembler.cpp + ) Index: lib/Target/Lanai/Disassembler/LLVMBuild.txt =================================================================== --- lib/Target/Lanai/Disassembler/LLVMBuild.txt +++ lib/Target/Lanai/Disassembler/LLVMBuild.txt @@ -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 Index: lib/Target/Lanai/Disassembler/LanaiDisassembler.h =================================================================== --- lib/Target/Lanai/Disassembler/LanaiDisassembler.h +++ lib/Target/Lanai/Disassembler/LanaiDisassembler.h @@ -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 Bytes, + uint64_t Address, raw_ostream &VStream, + raw_ostream &CStream) const override; +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_DISASSEMBLER_LANAIDISASSEMBLER_H Index: lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp =================================================================== --- lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp +++ lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp @@ -0,0 +1,229 @@ +//===- 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 decodeNeg6OpValue(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +#include "LanaiGenDisassemblerTables.inc" + +static DecodeStatus readInstruction32(ArrayRef 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 (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); + } + } else if (isSPLSOpcode(Instr.getOpcode())) { + PqShift = 10; + } + + 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 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(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 decodeNeg6OpValue(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::createImm(-SignExtend32<6>(Insn))); + return MCDisassembler::Success; +} Index: lib/Target/Lanai/InstPrinter/CMakeLists.txt =================================================================== --- lib/Target/Lanai/InstPrinter/CMakeLists.txt +++ lib/Target/Lanai/InstPrinter/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMLanaiInstPrinter + LanaiInstPrinter.cpp + ) Index: lib/Target/Lanai/InstPrinter/LLVMBuild.txt =================================================================== --- lib/Target/Lanai/InstPrinter/LLVMBuild.txt +++ lib/Target/Lanai/InstPrinter/LLVMBuild.txt @@ -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 Index: lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h =================================================================== --- lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h +++ lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h @@ -0,0 +1,65 @@ +//= 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 printNeg6ImmOperand(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 Index: lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp =================================================================== --- lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp +++ lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp @@ -0,0 +1,326 @@ +//===-- 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(&Expr)) + SRE = dyn_cast(BE->getLHS()); + else if (isa(&Expr)) { + SRE = dyn_cast(&Expr); + } else { + SRE = dyn_cast(&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); + } +} + +void LanaiInstPrinter::printNeg6ImmOperand(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); + } +} + +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 +void printMemoryImmediateOffset(const MCAsmInfo &MAI, const MCOperand &OffsetOp, + raw_ostream &Ostream) { + assert((OffsetOp.isImm() || OffsetOp.isExpr()) && "Immediate expected"); + if (OffsetOp.isImm()) { + assert(isInt(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(MI->getOperand(OpNo).getImm()); + Ostream << lanaiCondCodeToString(static_cast(CC)); +} Index: lib/Target/Lanai/LLVMBuild.txt =================================================================== --- lib/Target/Lanai/LLVMBuild.txt +++ lib/Target/Lanai/LLVMBuild.txt @@ -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 Index: lib/Target/Lanai/Lanai.h =================================================================== --- lib/Target/Lanai/Lanai.h +++ lib/Target/Lanai/Lanai.h @@ -0,0 +1,55 @@ +//===-- 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(); + +// createLanaiSaveReturnAddressPass - This pass inserts an instruction +// immediately before call instructions to save the return address. +FunctionPass *createLanaiSaveReturnAddressPass(); + +extern Target TheLanaiTarget; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_LANAI_H Index: lib/Target/Lanai/Lanai.td =================================================================== --- lib/Target/Lanai/Lanai.td +++ lib/Target/Lanai/Lanai.td @@ -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]; +} Index: lib/Target/Lanai/LanaiAluCode.h =================================================================== --- lib/Target/Lanai/LanaiAluCode.h +++ lib/Target/Lanai/LanaiAluCode.h @@ -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(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 Index: lib/Target/Lanai/LanaiAsmPrinter.cpp =================================================================== --- lib/Target/Lanai/LanaiAsmPrinter.cpp +++ lib/Target/Lanai/LanaiAsmPrinter.cpp @@ -0,0 +1,207 @@ +//===-- 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/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 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); +}; +} // 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(""); + } +} + +// 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::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 { + customEmitInstruction(&*I); + ++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(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 X(TheLanaiTarget); +} Index: lib/Target/Lanai/LanaiCallingConv.td =================================================================== --- lib/Target/Lanai/LanaiCallingConv.td +++ lib/Target/Lanai/LanaiCallingConv.td @@ -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>, + + // Put argument in registers if marked 'inreg' and not a vararg call. + CCIfNotVarArg>>>, + + // 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>, + + // Put arguments in registers. + CCIfNotVarArg>>, + + // 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)>; Index: lib/Target/Lanai/LanaiCondCode.h =================================================================== --- lib/Target/Lanai/LanaiCondCode.h +++ lib/Target/Lanai/LanaiCondCode.h @@ -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(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 Index: lib/Target/Lanai/LanaiDelaySlotFiller.cpp =================================================================== --- lib/Target/Lanai/LanaiDelaySlotFiller.cpp +++ lib/Target/Lanai/LanaiDelaySlotFiller.cpp @@ -0,0 +1,256 @@ +//===-- 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 + 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 LanaiSubtarget *Subtarget; + const TargetInstrInfo *TII; + 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 &F) override { + bool Changed = false; + Subtarget = &F.getSubtarget(); + TII = Subtarget->getInstrInfo(); + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) + Changed |= runOnMachineBasicBlock(*FI); + return Changed; + } + + void insertDefsUses(MachineBasicBlock::instr_iterator MI, + SmallSet &RegDefs, + SmallSet &RegUses); + + bool isRegInSet(SmallSet &RegSet, unsigned Reg); + + bool delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad, + bool &SawStore, SmallSet &RegDefs, + SmallSet &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 RegDefs; + SmallSet 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 &RegDefs, + SmallSet &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 &RegDefs, + SmallSet &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(); + + // Add RCA to RegDefs to prevent users of RCA from going into delay slot. + if (MI->isCall()) + RegDefs.insert(Lanai::RCA); + + // Add RCA to RegUses to prevent definers of RCA from going into delay slot. + if (MI->isReturn()) + RegUses.insert(Lanai::RCA); + + 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 &RegSet, unsigned Reg) { + // Check Reg and all aliased Registers. + for (MCRegAliasIterator AI(Reg, Subtarget->getRegisterInfo(), true); + AI.isValid(); ++AI) + if (RegSet.count(*AI)) + return true; + return false; +} Index: lib/Target/Lanai/LanaiFrameLowering.h =================================================================== --- lib/Target/Lanai/LanaiFrameLowering.h +++ lib/Target/Lanai/LanaiFrameLowering.h @@ -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 Index: lib/Target/Lanai/LanaiFrameLowering.cpp =================================================================== --- lib/Target/Lanai/LanaiFrameLowering.cpp +++ lib/Target/Lanai/LanaiFrameLowering.cpp @@ -0,0 +1,221 @@ +//===-- 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(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(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(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(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()); + } +} Index: lib/Target/Lanai/LanaiISelDAGToDAG.cpp =================================================================== --- lib/Target/Lanai/LanaiISelDAGToDAG.cpp +++ lib/Target/Lanai/LanaiISelDAGToDAG.cpp @@ -0,0 +1,351 @@ +//===-- 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 { + // TM - Keep a reference to LanaiTargetMachine. + LanaiTargetMachine &TM; + + // Subtarget - Keep a pointer to the LanaiSubtarget around so that we can + // make the right decision when generating code for different targets. + const LanaiSubtarget *Subtarget; + +public: + explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine) + : SelectionDAGISel(TargetMachine), TM(TargetMachine) {} + + bool runOnMachineFunction(MachineFunction &MF) override { + Subtarget = &MF.getSubtarget(); + 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 &OutOps) override; + +private: +// Include the pieces autogenerated from the target description. +#include "LanaiGenDAGISel.inc" + + // getTargetMachine - Return a reference to the TargetMachine, casted + // to the target-specific type. + const LanaiTargetMachine &getTargetMachine() { + return static_cast(TM); + } + + // getInstrInfo - Return a reference to the TargetInstrInfo, casted + // to the target-specific type. + const LanaiInstrInfo *getInstrInfo() { return Subtarget->getInstrInfo(); } + + // 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(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(Addr)) { + // Loading from a constant address. + 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(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(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(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(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) { + if (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(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(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 &OutOps) { + SDValue Op0, Op1, AluOp; + switch (ConstraintCode) { + case InlineAsm::Constraint_o: // offsetable ?? + case InlineAsm::Constraint_v: // not offsetable ?? + 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(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); +} Index: lib/Target/Lanai/LanaiISelLowering.h =================================================================== --- lib/Target/Lanai/LanaiISelLowering.h +++ lib/Target/Lanai/LanaiISelLowering.h @@ -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 "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 LanaiTargetMachine; + +class LanaiTargetLowering : public TargetLowering { +public: + explicit LanaiTargetLowering(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 + 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 &Ops, + SelectionDAG &DAG) const override; + +private: + const LanaiSubtarget *Subtarget; + + SDValue LowerCCCCallTo(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool IsVarArg, + bool IsTailCall, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + const SmallVectorImpl &Ins, SDLoc dl, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerCCCArguments(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, SDLoc DL, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, SDLoc DL, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const override; + + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, + SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; + + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, SDLoc DL, + SelectionDAG &DAG) const override; +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_LANAIISELLOWERING_H Index: lib/Target/Lanai/LanaiISelLowering.cpp =================================================================== --- lib/Target/Lanai/LanaiISelLowering.cpp +++ lib/Target/Lanai/LanaiISelLowering.cpp @@ -0,0 +1,1223 @@ +//===-- LanaiISelLowering.cpp - Lanai DAG Lowering Implementation ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the LanaiTargetLowering class. +// +//===----------------------------------------------------------------------===// + +#include "LanaiISelLowering.h" + +#include "Lanai.h" +#include "LanaiMachineFunctionInfo.h" +#include "LanaiSubtarget.h" +#include "LanaiTargetMachine.h" +#include "LanaiTargetObjectFile.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "lanai-lower" + +using namespace llvm; + +// Limit on number of instructions the lowered multiplication may have before a +// call to the library function should be generated instead. The threshold is +// currently set to 14 as this was the smallest threshold that resulted in all +// constant multiplications being lowered. A threshold of 5 covered all cases +// except for one multiplication which required 14. mulsi3 requires 16 +// instructions (including the prologue and epilogue but excluding instructions +// at call site). Until we can inline mulsi3, generating at most 14 instructions +// will be faster than invoking mulsi3. +static cl::opt LanaiLowerConstantMulThreshold( + "lanai-constant-mul-threshold", cl::Hidden, + cl::desc("Maximum number of instruction to generate when lowering constant " + "multiplication instead of calling library function [default=14]"), + cl::init(14)); + +LanaiTargetLowering::LanaiTargetLowering(TargetMachine *TM, + const LanaiSubtarget *STI) + : TargetLowering(*TM), Subtarget(STI) { + // Set up the register classes. + addRegisterClass(MVT::i32, &Lanai::GPRRegClass); + + // Compute derived properties from the register classes + computeRegisterProperties(Subtarget->getRegisterInfo()); + + setStackPointerRegisterToSaveRestore(Lanai::SP); + + setOperationAction(ISD::BR_CC, MVT::i32, Custom); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + setOperationAction(ISD::SETCC, MVT::i32, Custom); + setOperationAction(ISD::SELECT, MVT::i32, Expand); + setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); + + setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); + setOperationAction(ISD::BlockAddress, MVT::i32, Custom); + setOperationAction(ISD::JumpTable, MVT::i32, Custom); + setOperationAction(ISD::ConstantPool, MVT::i32, Custom); + + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom); + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + + setOperationAction(ISD::VASTART, MVT::Other, Custom); + setOperationAction(ISD::VAARG, MVT::Other, Expand); + setOperationAction(ISD::VACOPY, MVT::Other, Expand); + setOperationAction(ISD::VAEND, MVT::Other, Expand); + + setOperationAction(ISD::SDIV, MVT::i32, Expand); + setOperationAction(ISD::UDIV, MVT::i32, Expand); + setOperationAction(ISD::SDIVREM, MVT::i32, Expand); + setOperationAction(ISD::UDIVREM, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::UREM, MVT::i32, Expand); + + setOperationAction(ISD::MUL, MVT::i32, Custom); + setOperationAction(ISD::MULHU, MVT::i32, Expand); + setOperationAction(ISD::MULHS, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + + setOperationAction(ISD::ROTR, MVT::i32, Expand); + setOperationAction(ISD::ROTL, MVT::i32, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); + + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + setOperationAction(ISD::CTPOP, MVT::i32, Legal); + setOperationAction(ISD::CTLZ, MVT::i32, Legal); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Legal); + setOperationAction(ISD::CTTZ, MVT::i32, Legal); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Legal); + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); + + // Extended load operations for i1 types must be promoted + for (MVT VT : MVT::integer_valuetypes()) { + setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); + } + + // Function alignments (log2) + setMinFunctionAlignment(2); + setPrefFunctionAlignment(2); + + setJumpIsExpensive(true); + + // TODO: Setting the minimum jump table entries needed before a + // switch is transformed to a jump table to 100 to avoid creating jump tables + // as this was causing bad performance compared to a large group of if + // statements. Re-evaluate this on new benchmarks. + setMinimumJumpTableEntries(100); + + // Use fast calling convention for library functions. + for (int I = 0; I < RTLIB::UNKNOWN_LIBCALL; ++I) { + setLibcallCallingConv(static_cast(I), CallingConv::Fast); + } + + MaxStoresPerMemset = 16; // For @llvm.memset -> sequence of stores + MaxStoresPerMemsetOptSize = 8; + MaxStoresPerMemcpy = 16; // For @llvm.memcpy -> sequence of stores + MaxStoresPerMemcpyOptSize = 8; + MaxStoresPerMemmove = 16; // For @llvm.memmove -> sequence of stores + MaxStoresPerMemmoveOptSize = 8; +} + +SDValue LanaiTargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + case ISD::MUL: + return LowerMUL(Op, DAG); + case ISD::BR_CC: + return LowerBR_CC(Op, DAG); + case ISD::ConstantPool: + return LowerConstantPool(Op, DAG); + case ISD::GlobalAddress: + return LowerGlobalAddress(Op, DAG); + case ISD::BlockAddress: + return LowerBlockAddress(Op, DAG); + case ISD::JumpTable: + return LowerJumpTable(Op, DAG); + case ISD::SELECT_CC: + return LowerSELECT_CC(Op, DAG); + case ISD::SETCC: + return LowerSETCC(Op, DAG); + case ISD::VASTART: + return LowerVASTART(Op, DAG); + case ISD::DYNAMIC_STACKALLOC: + return LowerDYNAMIC_STACKALLOC(Op, DAG); + case ISD::RETURNADDR: + return LowerRETURNADDR(Op, DAG); + case ISD::FRAMEADDR: + return LowerFRAMEADDR(Op, DAG); + default: + llvm_unreachable("unimplemented operand"); + } +} +//===----------------------------------------------------------------------===// +// Lanai Inline Assembly Support +//===----------------------------------------------------------------------===// + +unsigned LanaiTargetLowering::getRegisterByName(const char *RegName, EVT VT, + SelectionDAG &DAG) const { + // Only unallocatable registers should be matched here. + unsigned Reg = StringSwitch(RegName) + .Case("pc", Lanai::PC) + .Case("sp", Lanai::SP) + .Case("fp", Lanai::FP) + .Case("rr1", Lanai::RR1) + .Case("r10", Lanai::R10) + .Case("rr2", Lanai::RR2) + .Case("r11", Lanai::R11) + .Case("rca", Lanai::RCA) + .Default(0); + + if (Reg) + return Reg; + report_fatal_error("Invalid register name global variable"); +} + +std::pair +LanaiTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, + MVT VT) const { + if (Constraint.size() == 1) { + // GCC Constraint Letters + switch (Constraint[0]) { + case 'r': // GENERAL_REGS + return std::make_pair(0U, &Lanai::GPRRegClass); + default: + break; + } + } + + return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); +} + +// Examine constraint type and operand type and determine a weight value. +// This object must already have been set up with the operand type +// and the current alternative constraint selected. +TargetLowering::ConstraintWeight +LanaiTargetLowering::getSingleConstraintMatchWeight( + AsmOperandInfo &Info, const char *Constraint) const { + ConstraintWeight Weight = CW_Invalid; + Value *CallOperandVal = Info.CallOperandVal; + // If we don't have a value, we can't do a match, + // but allow it at the lowest weight. + if (CallOperandVal == NULL) + return CW_Default; + // Look at the constraint type. + switch (*Constraint) { + case 'I': // signed 16 bit immediate + case 'J': // integer zero + case 'K': // unsigned 16 bit immediate + case 'L': // immediate in the range 0 to 31 + case 'M': // signed 32 bit immediate where lower 16 bits are 0 + case 'N': // signed 26 bit immediate + case 'O': // integer zero + if (isa(CallOperandVal)) + Weight = CW_Constant; + break; + default: + Weight = TargetLowering::getSingleConstraintMatchWeight(Info, Constraint); + break; + } + return Weight; +} + +// LowerAsmOperandForConstraint - Lower the specified operand into the Ops +// vector. If it is invalid, don't add anything to Ops. +void LanaiTargetLowering::LowerAsmOperandForConstraint( + SDValue Op, std::string &Constraint, std::vector &Ops, + SelectionDAG &DAG) const { + SDValue Result(0, 0); + + // Only support length 1 constraints for now. + if (Constraint.length() > 1) + return; + + char ConstraintLetter = Constraint[0]; + switch (ConstraintLetter) { + case 'I': // Signed 16 bit constant + // If this fails, the parent routine will give an error + if (ConstantSDNode *C = dyn_cast(Op)) { + if (isInt<16>(C->getSExtValue())) { + Result = DAG.getTargetConstant(C->getSExtValue(), SDLoc(C), + Op.getValueType()); + break; + } + } + return; + case 'J': // integer zero + case 'O': + if (ConstantSDNode *C = dyn_cast(Op)) { + if (C->getZExtValue() == 0) { + Result = DAG.getTargetConstant(0, SDLoc(C), Op.getValueType()); + break; + } + } + return; + case 'K': // unsigned 16 bit immediate + if (ConstantSDNode *C = dyn_cast(Op)) { + if (isUInt<16>(C->getZExtValue())) { + Result = DAG.getTargetConstant(C->getSExtValue(), SDLoc(C), + Op.getValueType()); + break; + } + } + return; + case 'L': // immediate in the range 0 to 31 + if (ConstantSDNode *C = dyn_cast(Op)) { + if (C->getZExtValue() <= 31) { + Result = DAG.getTargetConstant(C->getZExtValue(), SDLoc(C), + Op.getValueType()); + break; + } + } + return; + case 'M': // signed 32 bit immediate where lower 16 bits are 0 + if (ConstantSDNode *C = dyn_cast(Op)) { + int64_t Val = C->getSExtValue(); + if ((isInt<32>(Val)) && ((Val & 0xffff) == 0)) { + Result = DAG.getTargetConstant(Val, SDLoc(C), Op.getValueType()); + break; + } + } + return; + case 'N': // signed 26 bit immediate + if (ConstantSDNode *C = dyn_cast(Op)) { + int64_t Val = C->getSExtValue(); + if ((Val >= -33554432) && (Val <= 33554431)) { + Result = DAG.getTargetConstant(Val, SDLoc(C), Op.getValueType()); + break; + } + } + return; + default: + break; // This will fall through to the generic implementation + } + + if (Result.getNode()) { + Ops.push_back(Result); + return; + } + + TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +#include "LanaiGenCallingConv.inc" + +static unsigned NumFixedArgs; +static bool CC_Lanai32_VarArg(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + // Handle fixed arguments with default CC. + // Note: Both the default and fast CC handle VarArg the same and hence the + // calling convention of the function is not considered here. + if (ValNo < NumFixedArgs) { + return CC_Lanai32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State); + } + + // Promote i8/i16 args to i32 + if (LocVT == MVT::i8 || LocVT == MVT::i16) { + LocVT = MVT::i32; + if (ArgFlags.isSExt()) + LocInfo = CCValAssign::SExt; + else if (ArgFlags.isZExt()) + LocInfo = CCValAssign::ZExt; + else + LocInfo = CCValAssign::AExt; + } + + // VarArgs get passed on stack + unsigned Offset = State.AllocateStack(4, 4); + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + return false; +} + +SDValue LanaiTargetLowering::LowerFormalArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + switch (CallConv) { + case CallingConv::C: + case CallingConv::Fast: + return LowerCCCArguments(Chain, CallConv, IsVarArg, Ins, DL, DAG, InVals); + default: + llvm_unreachable("Unsupported calling convention"); + } +} + +SDValue LanaiTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const { + SelectionDAG &DAG = CLI.DAG; + SDLoc &DL = CLI.DL; + SmallVectorImpl &Outs = CLI.Outs; + SmallVectorImpl &OutVals = CLI.OutVals; + SmallVectorImpl &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &IsTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool IsVarArg = CLI.IsVarArg; + + // Lanai target does not yet support tail call optimization. + IsTailCall = false; + + switch (CallConv) { + case CallingConv::Fast: + case CallingConv::C: + return LowerCCCCallTo(Chain, Callee, CallConv, IsVarArg, IsTailCall, Outs, + OutVals, Ins, DL, DAG, InVals); + default: + llvm_unreachable("Unsupported calling convention"); + } +} + +// LowerCCCArguments - transform physical registers into virtual registers and +// generate load operations for arguments places on the stack. +SDValue LanaiTargetLowering::LowerCCCArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + LanaiMachineFunctionInfo *LanaiMFI = MF.getInfo(); + + // Assign locations to all of the incoming arguments. + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, + *DAG.getContext()); + if (CallConv == CallingConv::Fast) { + CCInfo.AnalyzeFormalArguments(Ins, CC_Lanai32_Fast); + } else { + CCInfo.AnalyzeFormalArguments(Ins, CC_Lanai32); + } + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + if (VA.isRegLoc()) { + // Arguments passed in registers + EVT RegVT = VA.getLocVT(); + switch (RegVT.getSimpleVT().SimpleTy) { + case MVT::i32: { + unsigned VReg = RegInfo.createVirtualRegister(&Lanai::GPRRegClass); + RegInfo.addLiveIn(VA.getLocReg(), VReg); + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, VReg, RegVT); + + // If this is an 8/16-bit value, it is really passed promoted to 32 + // bits. Insert an assert[sz]ext to capture this, then truncate to the + // right size. + if (VA.getLocInfo() == CCValAssign::SExt) + ArgValue = DAG.getNode(ISD::AssertSext, DL, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + ArgValue = DAG.getNode(ISD::AssertZext, DL, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + + if (VA.getLocInfo() != CCValAssign::Full) + ArgValue = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), ArgValue); + + InVals.push_back(ArgValue); + break; + } + default: + DEBUG(dbgs() << "LowerFormalArguments Unhandled argument type: " + << RegVT.getSimpleVT().SimpleTy << "\n"); + llvm_unreachable("unhandled argument type"); + } + } else { + // Sanity check + assert(VA.isMemLoc()); + // Load the argument to a virtual register + unsigned ObjSize = VA.getLocVT().getSizeInBits() / 8; + // Check that the argument fits in stack slot + if (ObjSize > 4) { + errs() << "LowerFormalArguments Unhandled argument type: " + << EVT(VA.getLocVT()).getEVTString() << "\n"; + } + // Create the frame index object for this incoming parameter... + int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset(), true); + + // Create the SelectionDAG nodes corresponding to a load + // from this parameter + SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); + InVals.push_back(DAG.getLoad( + VA.getLocVT(), DL, Chain, FIN, + MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), + false, false, false, 0)); + } + } + + // The Lanai ABI for returning structs by value requires that we copy + // the sret argument into rv for the return. Save the argument into + // a virtual register so that we can access it from the return points. + if (MF.getFunction()->hasStructRetAttr()) { + unsigned Reg = LanaiMFI->getSRetReturnReg(); + if (!Reg) { + Reg = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i32)); + LanaiMFI->setSRetReturnReg(Reg); + } + SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), DL, Reg, InVals[0]); + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Copy, Chain); + } + + if (IsVarArg) { + // Record the frame index of the first variable argument + // which is a value necessary to VASTART. + int FI = MFI->CreateFixedObject(4, CCInfo.getNextStackOffset(), true); + LanaiMFI->setVarArgsFrameIndex(FI); + } + + return Chain; +} + +SDValue +LanaiTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + SDLoc DL, SelectionDAG &DAG) const { + // CCValAssign - represent the assignment of the return value to a location + SmallVector RVLocs; + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, + *DAG.getContext()); + + // Analize return values. + CCInfo.AnalyzeReturn(Outs, RetCC_Lanai32); + + SDValue Flag; + SmallVector RetOps(1, Chain); + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Flag); + + // Guarantee that all emitted copies are stuck together with flags. + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + + // The Lanai ABI for returning structs by value requires that we copy + // the sret argument into rv for the return. We saved the argument into + // a virtual register in the entry block, so now we copy the value out + // and into rv. + if (DAG.getMachineFunction().getFunction()->hasStructRetAttr()) { + MachineFunction &MF = DAG.getMachineFunction(); + LanaiMachineFunctionInfo *LanaiMFI = MF.getInfo(); + unsigned Reg = LanaiMFI->getSRetReturnReg(); + assert(Reg && + "SRetReturnReg should have been set in LowerFormalArguments()."); + SDValue Val = + DAG.getCopyFromReg(Chain, DL, Reg, getPointerTy(DAG.getDataLayout())); + + Chain = DAG.getCopyToReg(Chain, DL, Lanai::RV, Val, Flag); + Flag = Chain.getValue(1); + RetOps.push_back( + DAG.getRegister(Lanai::RV, getPointerTy(DAG.getDataLayout()))); + } + + RetOps[0] = Chain; // Update chain + + unsigned Opc = LanaiISD::RET_FLAG; + if (Flag.getNode()) + RetOps.push_back(Flag); + + // Return Void + return DAG.getNode(Opc, DL, MVT::Other, + ArrayRef(&RetOps[0], RetOps.size())); +} + +// LowerCCCCallTo - functions arguments are copied from virtual regs to +// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. +SDValue LanaiTargetLowering::LowerCCCCallTo( + SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool IsVarArg, + bool IsTailCall, const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + const SmallVectorImpl &Ins, SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + // Analyze operands of the call, assigning locations to each operand. + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, + *DAG.getContext()); + GlobalAddressSDNode *G = dyn_cast(Callee); + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + + NumFixedArgs = 0; + if (IsVarArg && G) { + const Function *CalleeFn = dyn_cast(G->getGlobal()); + if (CalleeFn) + NumFixedArgs = CalleeFn->getFunctionType()->getNumParams(); + } + if (NumFixedArgs) { + CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32_VarArg); + } else { + if (CallConv == CallingConv::Fast) { + CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32_Fast); + } else { + CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32); + } + } + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = CCInfo.getNextStackOffset(); + + // Create local copies for byval args. + SmallVector ByValArgs; + for (unsigned I = 0, E = Outs.size(); I != E; ++I) { + ISD::ArgFlagsTy Flags = Outs[I].Flags; + if (!Flags.isByVal()) + continue; + + SDValue Arg = OutVals[I]; + unsigned Size = Flags.getByValSize(); + unsigned Align = Flags.getByValAlign(); + + int FI = MFI->CreateStackObject(Size, Align, false); + SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + SDValue SizeNode = DAG.getConstant(Size, DL, MVT::i32); + + Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Align, + /*IsVolatile=*/false, + /*AlwaysInline=*/false, + /*IsTailCall=*/false, MachinePointerInfo(), + MachinePointerInfo()); + ByValArgs.push_back(FIPtr); + } + + Chain = DAG.getCALLSEQ_START( + Chain, + DAG.getConstant(NumBytes, DL, getPointerTy(DAG.getDataLayout()), true), + DL); + + SmallVector, 4> RegsToPass; + SmallVector MemOpChains; + SDValue StackPtr; + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned I = 0, J = 0, E = ArgLocs.size(); I != E; ++I) { + CCValAssign &VA = ArgLocs[I]; + SDValue Arg = OutVals[I]; + ISD::ArgFlagsTy Flags = Outs[I].Flags; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + case CCValAssign::Full: + break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg); + break; + default: + llvm_unreachable("Unknown loc info!"); + } + + // Use local copy if it is a byval arg. + if (Flags.isByVal()) + Arg = ByValArgs[J++]; + + // Arguments that can be passed on register must be kept at RegsToPass + // vector + if (VA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + } else { + assert(VA.isMemLoc()); + + if (StackPtr.getNode() == 0) + StackPtr = DAG.getCopyFromReg(Chain, DL, Lanai::SP, + getPointerTy(DAG.getDataLayout())); + + SDValue PtrOff = + DAG.getNode(ISD::ADD, DL, getPointerTy(DAG.getDataLayout()), StackPtr, + DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); + + MemOpChains.push_back(DAG.getStore( + Chain, DL, Arg, PtrOff, MachinePointerInfo(), false, false, 0)); + } + } + + // Transform all store nodes into one single node because all store nodes are + // independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, + ArrayRef(&MemOpChains[0], MemOpChains.size())); + + SDValue InFlag; + + // Build a sequence of copy-to-reg nodes chained together with token chain and + // flag operands which copy the outgoing args into registers. The InFlag in + // necessary since all emitted instructions must be stuck together. + for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { + Chain = DAG.getCopyToReg(Chain, DL, RegsToPass[I].first, + RegsToPass[I].second, InFlag); + InFlag = Chain.getValue(1); + } + + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + // Likewise ExternalSymbol -> TargetExternalSymbol. + uint8_t OpFlag = LanaiII::MO_NO_FLAG; + if (G) { + Callee = DAG.getTargetGlobalAddress( + G->getGlobal(), DL, getPointerTy(DAG.getDataLayout()), 0, OpFlag); + } else if (ExternalSymbolSDNode *E = dyn_cast(Callee)) { + Callee = DAG.getTargetExternalSymbol( + E->getSymbol(), getPointerTy(DAG.getDataLayout()), OpFlag); + } + + // Returns a chain & a flag for retval copy to use. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add a register mask operand representing the call-preserved registers. + // TODO: Should return-twice functions be handled? + const LanaiRegisterInfo *TRI = Subtarget->getRegisterInfo(); + const uint32_t *Mask = + TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) + Ops.push_back(DAG.getRegister(RegsToPass[I].first, + RegsToPass[I].second.getValueType())); + + if (InFlag.getNode()) + Ops.push_back(InFlag); + + Chain = DAG.getNode(LanaiISD::CALL, DL, NodeTys, + ArrayRef(&Ops[0], Ops.size())); + InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END( + Chain, + DAG.getConstant(NumBytes, DL, getPointerTy(DAG.getDataLayout()), true), + DAG.getConstant(0, DL, getPointerTy(DAG.getDataLayout()), true), InFlag, + DL); + InFlag = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return LowerCallResult(Chain, InFlag, CallConv, IsVarArg, Ins, DL, DAG, + InVals); +} + +// LowerCallResult - Lower the result values of a call into the +// appropriate copies out of appropriate physical registers. +SDValue LanaiTargetLowering::LowerCallResult( + SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + // Assign locations to each value returned by this call. + SmallVector RVLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, + *DAG.getContext()); + + CCInfo.AnalyzeCallResult(Ins, RetCC_Lanai32); + + // Copy all of the result registers out of their specified physreg. + for (unsigned I = 0; I != RVLocs.size(); ++I) { + Chain = DAG.getCopyFromReg(Chain, DL, RVLocs[I].getLocReg(), + RVLocs[I].getValVT(), InFlag) + .getValue(1); + InFlag = Chain.getValue(2); + InVals.push_back(Chain.getValue(0)); + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// Custom Lowerings +//===----------------------------------------------------------------------===// + +static LPCC::CondCode IntCondCCodeToICC(ISD::CondCode SetCCOpcode, SDLoc DL, + SDValue &LHS, SDValue &RHS, + SelectionDAG &DAG) { + // For integer, only the SETEQ, SETNE, SETLT, SETLE, SETGT, SETGE, SETULT, + // SETULE, SETUGT, and SETUGE opcodes are used (see CodeGen/ISDOpcodes.h) + // and Lanai only supports integer comparisons, so only provide definitions + // for them. + switch (SetCCOpcode) { + case ISD::SETEQ: + return LPCC::ICC_EQ; + case ISD::SETGT: + if (ConstantSDNode *RHSC = dyn_cast(RHS)) { + if (RHSC->getZExtValue() == 0xFFFFFFFF) { + // X > -1 -> X >= 0 -> is_plus(X) + RHS = DAG.getConstant(0, DL, RHS.getValueType()); + return LPCC::ICC_PL; + } + } + return LPCC::ICC_GT; + case ISD::SETUGT: + return LPCC::ICC_UGT; + case ISD::SETLT: + if (ConstantSDNode *RHSC = dyn_cast(RHS)) { + if (RHSC->getZExtValue() == 0) { + // X < 0 -> is_minus(X) + return LPCC::ICC_MI; + } + } + return LPCC::ICC_LT; + case ISD::SETULT: + return LPCC::ICC_ULT; + case ISD::SETLE: + if (ConstantSDNode *RHSC = dyn_cast(RHS)) { + if (RHSC->getZExtValue() == 0xFFFFFFFF) { + // X <= -1 -> X < 0 -> is_minus(X) + RHS = DAG.getConstant(0, DL, RHS.getValueType()); + return LPCC::ICC_MI; + } + } + return LPCC::ICC_LE; + case ISD::SETULE: + return LPCC::ICC_ULE; + case ISD::SETGE: + if (ConstantSDNode *RHSC = dyn_cast(RHS)) { + if (RHSC->getZExtValue() == 0) { + // X >= 0 -> is_plus(X) + return LPCC::ICC_PL; + } + } + return LPCC::ICC_GE; + case ISD::SETUGE: + return LPCC::ICC_UGE; + case ISD::SETNE: + return LPCC::ICC_NE; + case ISD::SETONE: + case ISD::SETUNE: + case ISD::SETOGE: + case ISD::SETOLE: + case ISD::SETOLT: + case ISD::SETOGT: + case ISD::SETOEQ: + case ISD::SETUEQ: + case ISD::SETO: + case ISD::SETUO: + llvm_unreachable("Unsupported comparison."); + default: + llvm_unreachable("Unknown integer condition code!"); + } +} + +SDValue LanaiTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue Dest = Op.getOperand(4); + SDLoc DL(Op); + + SDValue TargetCC = + DAG.getConstant(IntCondCCodeToICC(CC, DL, LHS, RHS, DAG), DL, MVT::i32); + SDValue Flag = + DAG.getNode(LanaiISD::SET_FLAG, DL, MVT::Glue, LHS, RHS, TargetCC); + + return DAG.getNode(LanaiISD::BR_CC, DL, Op.getValueType(), Chain, Dest, + TargetCC, Flag); +} + +SDValue LanaiTargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const { + EVT VT = Op->getValueType(0); + if (VT != MVT::i32) + return SDValue(); + + ConstantSDNode *C = dyn_cast(Op->getOperand(1)); + if (!C) + return SDValue(); + + int64_t MulAmt = C->getSExtValue(); + int32_t HighestOne = -1; + uint32_t NonzeroEntries = 0; + int SignedDigit[32] = {0}; + + // Convert to non-adjacent form (NAF) signed-digit representation. + // NAF is a signed-digit form where no adjacent digits are non-zero. It is the + // minimal Hamming weight representation of a number (on average 1/3 of the + // digits will be non-zero vs 1/2 for regular binary representation). And as + // the non-zero digits will be the only digits contributing to the instruction + // count, this is desirable. The next loop converts it to NAF (following the + // approach in 'Guide to Elliptic Curve Cryptography' [ISBN: 038795273X]) by + // choosing the non-zero coefficients such that the resulting quotient is + // divisible by 2 which will cause the next coefficient to be zero. + int64_t E = std::abs(MulAmt); + int S = (MulAmt < 0 ? -1 : 1); + int I = 0; + while (E > 0) { + int ZI = 0; + if (E % 2 == 1) { + ZI = 2 - (E % 4); + if (ZI != 0) { + ++NonzeroEntries; + } + } + SignedDigit[I] = S * ZI; + if (SignedDigit[I] == 1) { + HighestOne = I; + } + E = (E - ZI) / 2; + ++I; + } + + // Compute number of instructions required. Due to differences in lowering + // between the different processors this count is not exact. + // Start by assuming a shift and a add/sub for every non-zero entry (hence + // every non-zero entry requires 1 shift and 1 add/sub except for the first + // entry). + int32_t InstrRequired = 2 * NonzeroEntries - 1; + // Correct possible over-adding due to shift by 0 (which is not emitted). + if (std::abs(MulAmt) % 2 == 1) + --InstrRequired; + // Return if the form generated would exceed the instruction threshold. + if (InstrRequired > LanaiLowerConstantMulThreshold) + return SDValue(); + + SDValue Res; + SDLoc DL(Op); + SDValue V = Op->getOperand(0); + + // Initialize the running sum. Set the running sum to the maximal shifted + // positive value (i.e., largest i such that zi == 1 and MulAmt has V<(Op.getOperand(2))->get(); + SDLoc DL(Op); + + SDValue TargetCC = + DAG.getConstant(IntCondCCodeToICC(CC, DL, LHS, RHS, DAG), DL, MVT::i32); + SDValue Flag = + DAG.getNode(LanaiISD::SET_FLAG, DL, MVT::Glue, LHS, RHS, TargetCC); + + return DAG.getNode(LanaiISD::SETCC, DL, Op.getValueType(), TargetCC, Flag); +} + +SDValue LanaiTargetLowering::LowerSELECT_CC(SDValue Op, + SelectionDAG &DAG) const { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + SDValue TrueV = Op.getOperand(2); + SDValue FalseV = Op.getOperand(3); + ISD::CondCode CC = cast(Op.getOperand(4))->get(); + SDLoc DL(Op); + + SDValue TargetCC = + DAG.getConstant(IntCondCCodeToICC(CC, DL, LHS, RHS, DAG), DL, MVT::i32); + SDValue Flag = + DAG.getNode(LanaiISD::SET_FLAG, DL, MVT::Glue, LHS, RHS, TargetCC); + + SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); + return DAG.getNode(LanaiISD::SELECT_CC, DL, VTs, TrueV, FalseV, TargetCC, + Flag); +} + +SDValue LanaiTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + LanaiMachineFunctionInfo *FuncInfo = MF.getInfo(); + + SDLoc DL(Op); + SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), + getPointerTy(DAG.getDataLayout())); + + // vastart just stores the address of the VarArgsFrameIndex slot into the + // memory location argument. + const Value *SV = cast(Op.getOperand(2))->getValue(); + return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1), + MachinePointerInfo(SV), false, false, 0); +} + +SDValue LanaiTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, + SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + SDValue Size = Op.getOperand(1); + SDLoc DL(Op); + + unsigned SPReg = getStackPointerRegisterToSaveRestore(); + + // Get a reference to the stack pointer. + SDValue StackPointer = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32); + + // Subtract the dynamic size from the actual stack size to + // obtain the new stack size. + SDValue Sub = DAG.getNode(ISD::SUB, DL, MVT::i32, StackPointer, Size); + + // + // For Lanai, the outgoing memory arguments area should be on top of the + // alloca area on the stack i.e., the outgoing memory arguments should be + // at a lower address than the alloca area. Move the alloca area down the + // stack by adding back the space reserved for outgoing arguments to SP + // here. + // + // We do not know what the size of the outgoing args is at this point. + // So, we add a pseudo instruction ADJDYNALLOC that will adjust the + // stack pointer. We replace this instruction with on that has the correct, + // known offset in emitPrologue(). + SDValue ArgAdjust = DAG.getNode(LanaiISD::ADJDYNALLOC, DL, MVT::i32, Sub); + + // The Sub result contains the new stack start address, so it + // must be placed in the stack pointer register. + SDValue CopyChain = DAG.getCopyToReg(Chain, DL, SPReg, Sub); + + SDValue Ops[2] = {ArgAdjust, CopyChain}; + return DAG.getMergeValues(Ops, DL); +} + +SDValue LanaiTargetLowering::LowerRETURNADDR(SDValue Op, + SelectionDAG &DAG) const { + const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MFI->setReturnAddressIsTaken(true); + + EVT VT = Op.getValueType(); + SDLoc DL(Op); + unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); + if (Depth) { + SDValue FrameAddr = LowerFRAMEADDR(Op, DAG); + const unsigned Offset = -4; + SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, + DAG.getIntPtrConstant(Offset, DL)); + return DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo(), + false, false, false, 0); + } + + // Return the link register, which contains the return address. + // Mark it an implicit live-in. + unsigned Reg = MF.addLiveIn(TRI->getRARegister(), getRegClassFor(MVT::i32)); + return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, VT); +} + +SDValue LanaiTargetLowering::LowerFRAMEADDR(SDValue Op, + SelectionDAG &DAG) const { + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setFrameAddressIsTaken(true); + + EVT VT = Op.getValueType(); + SDLoc DL(Op); + SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, Lanai::FP, VT); + unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); + while (Depth--) { + const unsigned Offset = -8; + SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, + DAG.getIntPtrConstant(Offset, DL)); + FrameAddr = DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, + MachinePointerInfo(), false, false, false, 0); + } + return FrameAddr; +} + +const char *LanaiTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + case LanaiISD::ADJDYNALLOC: + return "LanaiISD::ADJDYNALLOC"; + case LanaiISD::RET_FLAG: + return "LanaiISD::RET_FLAG"; + case LanaiISD::CALL: + return "LanaiISD::CALL"; + case LanaiISD::SELECT_CC: + return "LanaiISD::SELECT_CC"; + case LanaiISD::SETCC: + return "LanaiISD::SETCC"; + case LanaiISD::SET_FLAG: + return "LanaiISD::SET_FLAG"; + case LanaiISD::BR_CC: + return "LanaiISD::BR_CC"; + case LanaiISD::Wrapper: + return "LanaiISD::Wrapper"; + case LanaiISD::HI: + return "LanaiISD::HI"; + case LanaiISD::LO: + return "LanaiISD::LO"; + case LanaiISD::SMALL: + return "LanaiISD::SMALL"; + default: + return NULL; + } +} + +SDValue LanaiTargetLowering::LowerConstantPool(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + ConstantPoolSDNode *N = cast(Op); + const Constant *C = N->getConstVal(); + const LanaiTargetObjectFile *TLOF = + static_cast( + getTargetMachine().getObjFileLowering()); + + // If the code model is small or constant will be placed in the small section, + // then assume address will fit in 21-bits. + if (getTargetMachine().getCodeModel() == CodeModel::Small || + TLOF->isConstantInSmallSection(DAG.getDataLayout(), C, + getTargetMachine())) { + SDValue Small = DAG.getTargetConstantPool( + C, MVT::i32, N->getAlignment(), N->getOffset(), LanaiII::MO_NO_FLAG); + return DAG.getNode(ISD::OR, DL, MVT::i32, + DAG.getRegister(Lanai::R0, MVT::i32), + DAG.getNode(LanaiISD::SMALL, DL, MVT::i32, Small)); + } else { + uint8_t OpFlagHi = LanaiII::MO_ABS_HI; + uint8_t OpFlagLo = LanaiII::MO_ABS_LO; + + SDValue Hi = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), + N->getOffset(), OpFlagHi); + SDValue Lo = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), + N->getOffset(), OpFlagLo); + Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); + Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); + SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); + return Result; + } +} + +SDValue LanaiTargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + const GlobalValue *GV = cast(Op)->getGlobal(); + int64_t Offset = cast(Op)->getOffset(); + + const LanaiTargetObjectFile *TLOF = + static_cast( + getTargetMachine().getObjFileLowering()); + + // If the code model is small or global variable will be placed in the small + // section, then assume address will fit in 21-bits. + if (getTargetMachine().getCodeModel() == CodeModel::Small || + TLOF->isGlobalInSmallSection(GV, getTargetMachine())) { + SDValue Small = DAG.getTargetGlobalAddress( + GV, DL, getPointerTy(DAG.getDataLayout()), Offset, LanaiII::MO_NO_FLAG); + return DAG.getNode(ISD::OR, DL, MVT::i32, + DAG.getRegister(Lanai::R0, MVT::i32), + DAG.getNode(LanaiISD::SMALL, DL, MVT::i32, Small)); + } else { + uint8_t OpFlagHi = LanaiII::MO_ABS_HI; + uint8_t OpFlagLo = LanaiII::MO_ABS_LO; + + // Create the TargetGlobalAddress node, folding in the constant offset. + SDValue Hi = DAG.getTargetGlobalAddress( + GV, DL, getPointerTy(DAG.getDataLayout()), Offset, OpFlagHi); + SDValue Lo = DAG.getTargetGlobalAddress( + GV, DL, getPointerTy(DAG.getDataLayout()), Offset, OpFlagLo); + Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); + Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); + return DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); + } +} + +SDValue LanaiTargetLowering::LowerBlockAddress(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + const BlockAddress *BA = cast(Op)->getBlockAddress(); + + uint8_t OpFlagHi = LanaiII::MO_ABS_HI; + uint8_t OpFlagLo = LanaiII::MO_ABS_LO; + + SDValue Hi = DAG.getBlockAddress(BA, MVT::i32, true, OpFlagHi); + SDValue Lo = DAG.getBlockAddress(BA, MVT::i32, true, OpFlagLo); + Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); + Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); + SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); + return Result; +} + +SDValue LanaiTargetLowering::LowerJumpTable(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + JumpTableSDNode *JT = cast(Op); + + // If the code model is small assume address will fit in 21-bits. + if (getTargetMachine().getCodeModel() == CodeModel::Small) { + SDValue Small = DAG.getTargetJumpTable( + JT->getIndex(), getPointerTy(DAG.getDataLayout()), LanaiII::MO_NO_FLAG); + return DAG.getNode(ISD::OR, DL, MVT::i32, + DAG.getRegister(Lanai::R0, MVT::i32), + DAG.getNode(LanaiISD::SMALL, DL, MVT::i32, Small)); + } else { + uint8_t OpFlagHi = LanaiII::MO_ABS_HI; + uint8_t OpFlagLo = LanaiII::MO_ABS_LO; + + SDValue Hi = DAG.getTargetJumpTable( + JT->getIndex(), getPointerTy(DAG.getDataLayout()), OpFlagHi); + SDValue Lo = DAG.getTargetJumpTable( + JT->getIndex(), getPointerTy(DAG.getDataLayout()), OpFlagLo); + Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); + Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); + SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); + return Result; + } +} Index: lib/Target/Lanai/LanaiInstrFormats.td =================================================================== --- lib/Target/Lanai/LanaiInstrFormats.td +++ lib/Target/Lanai/LanaiInstrFormats.td @@ -0,0 +1,561 @@ +//===- LanaiInstrFormats.td - Lanai Instruction Formats ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +class InstLanai pattern> + : Instruction { + field bits<32> Inst; + field bits<32> SoftFail = 0; + let Size = 4; + + let Namespace = "Lanai"; + let DecoderNamespace = "Lanai"; + + bits<4> Opcode; + let Inst{31 - 28} = Opcode; + + dag OutOperandList = outs; + dag InOperandList = ins; + let AsmString = asmstr; + let Pattern = pattern; +} + +//------------------------------------------------------------------------------ +// Register Immediate (RI) +//------------------------------------------------------------------------------ +// Encoding: +// ----------------------------------------------------------------- +// |0.A.A.A| . . . . | . . . . |F.H| . . . . . . . . . . . . . . . | +// ----------------------------------------------------------------- +// opcode Rd Rs1 constant (16) +// +// Action: +// Rd <- Rs1 op constant +// +// Except for shift instructions, `H' determines whether the constant +// is in the high (1) or low (0) word. The other halfword is 0x0000, +// except for the `AND' instruction (`AAA' = 100), for which the other +// halfword is 0xFFFF, and shifts (`AAA' = 111), for which the constant is +// sign extended. +// +// `F' determines whether the instruction modifies (1) or does not +// modify (0) the program flags. +// +// `AAA' specifies the operation: `add' (000), `addc' (001), `sub' +// (010), `subb' (011), `and' (100), `or' (101), `xor' (110), or `shift' +// (111). For the shift, `H' specifies a logical (0) or arithmetic (1) +// shift. The amount and direction of the shift are determined by the +// sign extended constant interpreted as a two's complement number. The +// shift operation is defined only for the range of: +// 31 ... 0 -1 ... -31 +// \ / \ / +// left right +// shift shift +// +// If and only if the `F' bit is 1, RI instructions modify the +// condition bits, `Z' (Zero), `N' (Negative), `V' (oVerflow), and `C' +// (Carry), according to the result. If the flags are updated, they are +// updated as follows: +// `Z' +// is set if the result is zero and cleared otherwise. +// +// `N' +// is set to the most significant bit of the result. +// +// `V' +// For arithmetic instructions (`add', `addc', `sub', `subb') `V' is +// set if the sign (most significant) bits of the input operands are +// the same but different from the sign bit of the result and cleared +// otherwise. For other RI instructions, `V' is cleared. +// +// `C' +// For arithmetic instructions, `C' is set/cleared if there is/is_not +// a carry generated out of the most significant when performing the +// twos-complement addition (`sub(a,b) == a + ~b + 1', `subb(a,b) == +// a + ~b + `C''). For left shifts, `C' is set to the least +// significant bit discarded by the shift operation. For all other +// operations, `C' is cleared. +// +// A Jump is accomplished by `Rd' being `pc', and it has one shadow. +// +// The all-0s word is the instruction `R0 <- R0 + 0', which is a no-op. +class InstRI op, dag outs, dag ins, string asmstr, + list pattern> + : InstLanai, Sched<[WriteALU]> { + let Itinerary = IIC_ALU; + bits<5> Rd; + bits<5> Rs1; + bit F; + bit H; + bits<16> imm16; + + let Opcode{3} = 0; + let Opcode{2 - 0} = op; + let Inst{27 - 23} = Rd; + let Inst{22 - 18} = Rs1; + let Inst{17} = F; + let Inst{16} = H; + let Inst{15 - 0} = imm16; +} + +//------------------------------------------------------------------------------ +// Register Register (RR) +//------------------------------------------------------------------------------ +// Encoding: +// ----------------------------------------------------------------- +// |1.1.0.0| . . . . | . . . . |F.I| . . . . |B.B.B|J.J.J.J.J|D.D.D| +// ----------------------------------------------------------------- +// opcode Rd Rs1 Rs2 \ operation / +// +// Action: +// `Rd <- Rs1 op Rs2' iff condition DDDI is true. +// +// `DDDI' is as described for the BR instruction. +// +// `F' determines whether the instruction modifies (1) or does not +// modify (0) the program flags. +// +// `BBB' determines the operation: `add' (000), `addc' (001), `sub' +// (010), `subb' (011), `and' (100), `or' (101), `xor' (110), or "special" +// (111). The `JJJJJ' field is irrelevant except for special. +// +// `JJJJJ' determines which special operation is performed. `10---' +// is a logical shift, and `11---' is an arithmetic shift, and ‘00000` is +// the SELECT operation. The amount and direction of the shift are +// determined by the contents of `Rs2' interpreted as a two's complement +// number (in the same way as shifts in the Register-Immediate +// instructions in *Note RI::). For the SELECT operation, Rd gets Rs1 if +// condition DDDI is true, Rs2 otherwise. All other `JJJJJ' combinations +// are reserved for instructions that may be defined in the future. +// +// If the `F' bit is 1, RR instructions modify the condition bits, `Z' +// (Zero), `N' (Negative), `V' (oVerflow), and `C' (Carry), according to +// the result. All RR instructions modify the `Z', `N', and `V' flags. +// Except for arithmetic instructions (`add', `addc', `sub', `subb'), `V' +// is cleared. Only arithmetic instructions and shifts modify `C'. Right +// shifts clear C. +// +// DDDI is as described in the table for the BR instruction and only used for +// the select instruction. +// +// A Jump is accomplished by `Rd' being `pc', and it has one shadow. +class InstRR op, dag outs, dag ins, string asmstr, + list pattern> + : InstLanai, Sched<[WriteALU]> { + let Itinerary = IIC_ALU; + bits<5> Rd; + bits<5> Rs1; + bits<5> Rs2; + bit F; + bits<4> DDDI; + bits<5> JJJJJ; + + let Opcode = 0b1100; + let Inst{27 - 23} = Rd; + let Inst{22 - 18} = Rs1; + let Inst{17} = F; + let Inst{16} = DDDI{0}; + let Inst{15 - 11} = Rs2; + let Inst{10 - 8} = op; + let Inst{7 - 3} = JJJJJ; + let Inst{2 - 0} = DDDI{3 - 1}; +} + +//------------------------------------------------------------------------------ +// Register Memory (RM) +//------------------------------------------------------------------------------ +// Encoding: +// ----------------------------------------------------------------- +// |1.0.0.S| . . . . | . . . . |P.Q| . . . . . . . . . . . . . . . | +// ----------------------------------------------------------------- +// opcode Rd Rs1 constant (16) +// +// Action: +// Rd <- Memory(ea) (Load) see below for the +// Memory(ea) <- Rd (Store) definition of ea. +// +// `S' determines whether the instruction is a Load (0) or a Store (1). +// Loads appear in Rd one cycle after this instruction executes. If the +// following instruction reads Rd, that instruction will be delayed by 1 +// clock cycle. +// +// PQ operation +// -- ------------------------------------------ +// 00 ea = Rs1 +// 01 ea = Rs1, Rs1 <- Rs1 + constant +// 10 ea = Rs1 + constant +// 11 ea = Rs1 + constant, Rs1 <- Rs1 + constant +// +// The constant is sign-extended for this instruction. +// +// A Jump is accomplished by `Rd' being `pc', and it has *two* delay slots. +class InstRM pattern> + : InstLanai { + bits<5> Rd; + bits<5> Rs1; + bit P; + bit Q; + bits<16> imm16; + // Dummy variables to allow multiclass definition of RM and RRM + bits<2> YL; + bit E; + + let Opcode{3 - 1} = 0b100; + let Opcode{0} = S; + let Inst{27 - 23} = Rd; + let Inst{22 - 18} = Rs1; + let Inst{17} = P; + let Inst{16} = Q; + let Inst{15 - 0} = imm16; + + let PostEncoderMethod = "adjustPqBitsRmAndRrm"; +} + +//------------------------------------------------------------------------------ +// Register Register Memory (RRM) +//------------------------------------------------------------------------------ +// Encoding: +// ----------------------------------------------------------------- +// |1.0.1.S| . . . . | . . . . |P.Q| . . . . |B.B.B|J.J.J.J.J|Y.L.E| +// ----------------------------------------------------------------- +// opcode Rd Rs1 Rs2 \ operation / +// +// Action: +// Rd <- Memory(ea) (Load) see below for the +// Memory(ea) <- Rd (Store) definition of ea. +// +// The RRM instruction is identical to the RM (*note RM::.) instruction +// except that: +// +// 1. `Rs1 + constant' is replaced with `Rs1 op Rs2', where `op' is +// determined in the same way as in the RR instruction (*note RR::.) +// and +// +// 2. part-word memory accesses are allowed as specified below. +// +// If `BBB' != 111 (i.e.: For all but shift operations): +// If `YLE' = 01- => fuLl-word memory access +// If `YLE' = 00- => half-word memory access +// If `YLE' = 10- => bYte memory access +// If `YLE' = --1 => loads are zEro extended +// If `YLE' = --0 => loads are sign extended +// +// If `BBB' = 111 (For shift operations): +// fullword memory access are performed. +// +// All part-word loads write the least significant part of the +// destination register with the higher-order bits zero- or sign-extended. +// All part-word stores store the least significant part-word of the +// source register in the destination memory location. +// +// A Jump is accomplished by `Rd' being `pc', and it has *two* delay slots. +class InstRRM pattern> + : InstLanai { + bits<5> Rd; + bits<5> Rs1; + bits<5> Rs2; + bit P; + bit Q; + bits<3> BBB; + bits<5> JJJJJ; + bits<2> YL; + bit E; + + let Opcode{3 - 1} = 0b101; + let Opcode{0} = S; + let Inst{27 - 23} = Rd; + let Inst{22 - 18} = Rs1; + let Inst{17} = P; + let Inst{16} = Q; + let Inst{15 - 11} = Rs2; + let Inst{10 - 8} = BBB; + let Inst{7 - 3} = JJJJJ; + let Inst{2 - 1} = YL; + let Inst{0} = E; + + let PostEncoderMethod = "adjustPqBitsRmAndRrm"; +} + +//------------------------------------------------------------------------------ +// Conditional Branch (BR) +//------------------------------------------------------------------------------ +// Encoding: +// ----------------------------------------------------------------- +// |1.1.1.0|D.D.D| . . . . . . . . . . . . . . . . . . . . . . |0.I| +// ----------------------------------------------------------------- +// opcode condition constant (23) +// +// Action: +// if (condition) { `pc' <- 4*(zero-extended constant) } +// +// The BR instruction is an absolute branch. +// The constant is scaled as shown by its position in the instruction word such +// that it specifies word-aligned addresses in the range [0,2^25-4] +// +// The `DDDI' field selects the condition that causes the branch to be taken. +// (the `I' (Invert sense) bit inverts the sense of the condition): +// +// DDDI logical function [code, used for...] +// ---- -------------------------------------- ------------------------ +// 0000 1 [T, true] +// 0001 0 [F, false] +// 0010 C AND Z' [HI, high] +// 0011 C' OR Z [LS, low or same] +// 0100 C' [CC, carry cleared] +// 0101 C [CS, carry set] +// 0110 Z' [NE, not equal] +// 0111 Z [EQ, equal] +// 1000 V' [VC, oVerflow cleared] +// 1001 V [VS, oVerflow set] +// 1010 N' [PL, plus] +// 1011 N [MI, minus] +// 1100 (N AND V) OR (N' AND V') [GE, greater than or equal] +// 1101 (N AND V') OR (N' AND V) [LT, less than] +// 1110 (N AND V AND Z') OR (N' AND V' AND Z') [GT, greater than] +// 1111 (Z) OR (N AND V') OR (N' AND V) [LE, less than or equal] +// +// If the branch is not taken, the BR instruction is a no-op. If the branch is +// taken, the processor starts executing instructions at the branch target +// address *after* the processor has executed one more instruction. That is, +// the branch has one “branch delay slot”. Be very careful if you find yourself +// wanting to put a branch in a branch delays slot! +class InstBR pattern> + : InstLanai { + let Itinerary = IIC_ALU; + bits<25> addr; + bits<4> DDDI; + + let Opcode = 0b1110; + let Inst{27 - 25} = DDDI{3 - 1}; + let Inst{24 - 0} = addr; + // These instructions overwrite the last two address bits (which are assumed + // and ensured to be 0). + let Inst{1} = 0; + let Inst{0} = DDDI{0}; +} + +//------------------------------------------------------------------------------ +// Conditional Branch Relative (BRR) +//------------------------------------------------------------------------------ +// Encoding: +// ----------------------------------------------------------------- +// |1.1.1.0|D.D.D|1|-| . . . . |-.-| . . . . . . . . . . . . . |1.I| +// ----------------------------------------------------------------- +// opcode condition Rs1 constant (14) +// Action: +// if (condition) { ‘pc’ <- Rs1 + 4*sign-extended constant) } +// +// BRR behaves like BR, except the branch target address is a 16-bit PC relative +// offset. +class InstBRR pattern> + : InstLanai { + bits<4> DDDI; + bits<5> Rs1; + bits<16> imm16; + + let Opcode = 0b1110; + let Inst{27 - 25} = DDDI{3 - 1}; + let Inst{24} = 1; + let Inst{22 - 18} = Rs1; + let Inst{17 - 16} = 0; + let Inst{15 - 0} = imm16; + // Overwrite last two bits which have to be zero + let Inst{1} = 1; + let Inst{0} = DDDI{0}; + + // Set don't cares to zero + let Inst{23} = 0; +} + +//------------------------------------------------------------------------------ +// Conditional Set (SCC) +//------------------------------------------------------------------------------ +// Encoding: +// ----------------------------------------------------------------- +// |1.1.1.0|D.D.D|0.-| . . . . |-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-|1.I| +// ----------------------------------------------------------------- +// opcode condition Rs1 +// +// Action: +// Rs1 <- logical function result +// +// SCC sets dst_reg to the boolean result of computing the logical function +// specified by DDDI, as described in the table for the BR instruction. +class InstSCC pattern> + : InstLanai { + let Itinerary = IIC_ALU; + bits<5> Rs1; // dst_reg in documentation + bits<4> DDDI; + + let Opcode = 0b1110; + let Inst{27 - 25} = DDDI{3 - 1}; + let Inst{24} = 0; + let Inst{22 - 18} = Rs1; + let Inst{1} = 1; + let Inst{0} = DDDI{0}; + + // Set don't cares to zero + let Inst{23} = 0; + let Inst{17 - 2} = 0; +} + +//------------------------------------------------------------------------------ +// Special Load/Store (SLS) +//------------------------------------------------------------------------------ +// +// Encoding: +// ----------------------------------------------------------------- +// |1.1.1.1| . . . . | . . . . |0.S| . . . . . . . . . . . . . . . | +// ----------------------------------------------------------------- +// opcode Rd addr 5msb's address 16 lsb's +// +// Action: +// If S = 0 (LOAD): Rd <- Memory(address); +// If S = 1 (STORE): Memory(address) <- Rd +// +// The timing is the same as for RM (*note RM::.) and RRM (*note +// RRM::.) instructions. The two low-order bits of the 21-bit address are +// ignored. The address is zero extended. Fullword memory accesses are +// performed. +class InstSLS pattern> + : InstLanai { + bits<5> Rd; + bits<5> msb; + bits<16> lsb; + + let Opcode = 0b1111; + let Inst{27 - 23} = Rd; + let Inst{22 - 18} = msb; + let Inst{17} = 0; + let Inst{16} = S; + let Inst{15 - 0} = lsb; +} + +//------------------------------------------------------------------------------ +// Special Load Immediate (SLI) +//------------------------------------------------------------------------------ +// Encoding: +// ----------------------------------------------------------------- +// |1.1.1.1| . . . . | . . . . |1.0| . . . . . . . . . . . . . . . | +// ----------------------------------------------------------------- +// opcode Rd const 5msb's constant 16 lsb's +// +// Action: +// Rd <- constant +// +// The 21-bit constant is zero-extended. The timing is the same as the +// RM instruction (*note RM::.). +class InstSLI pattern> + : InstLanai { + bits<5> Rd; + bits<5> msb; + bits<16> lsb; + + let Opcode = 0b1111; + let Inst{27 - 23} = Rd; + let Inst{22 - 18} = msb; + let Inst{17} = 1; + let Inst{16} = 0; + let Inst{15 - 0} = lsb; +} + +//------------------------------------------------------------------------------ +// Special Part-Word Load/Store (SPLS) +//------------------------------------------------------------------------------ +// Encoding: +// ----------------------------------------------------------------- +// |1.1.1.1| . . . . | . . . . |1.1.0.Y.S.E.P.Q| . . . . . . . . . | +// ----------------------------------------------------------------- +// opcode Rd Rs1 constant (10) +// +// Action: +// If `YS' = 11 (bYte Store): +// Memory(ea) <- (least significant byte of Rr) +// If `YS' = 01 (halfword Store): +// Memory(ea) <- (least significant half-word of Rr) +// If `YS' = 10 (bYte load): Rr <- Memory(ea) +// If `YS' = 00 (halfword load): Rr <- Memory(ea) +// [Note: here ea is determined as in the the RM instruction. ] +// If `SE' = 01 then the value is zEro extended +// before being loaded into Rd. +// If `SE' = 00 then the value is sign extended +// before being loaded into Rd. +// +// `P' and `Q' are used to determine `ea' as in the RM instruction. The +// constant is sign extended. The timing is the same as the RM and RRM +// instructions. *Note RM:: and *Note RRM::. +// +// All part-word loads write the part-word into the least significant +// part of the destination register, with the higher-order bits zero- or +// sign-extended. All part-word stores store the least significant +// part-word of the source register into the destination memory location. +class InstSPLS pattern> + : InstLanai { + bits<5> Rd; + bits<5> Rs1; + bits<5> msb; + bit Y; + bit S; + bit E; + bit P; + bit Q; + bits<10> imm10; + + let Opcode = 0b1111; + let Inst{27 - 23} = Rd; + let Inst{22 - 18} = Rs1; + let Inst{17 - 15} = 0b110; + let Inst{14} = Y; + let Inst{13} = S; + let Inst{12} = E; + let Inst{11} = P; + let Inst{10} = Q; + let Inst{9 - 0} = imm10; + + let PostEncoderMethod = "adjustPqBitsSpls"; +} + +//------------------------------------------------------------------------------ +// Special instructions (popc, leadz, trailz) +//------------------------------------------------------------------------------ +// Encoding: +// ----------------------------------------------------------------- +// |1.1.0.1| Rd | Rs1 |F.-| . . . . | . . | . . . . | OP | +// ----------------------------------------------------------------- +// opcode Rd Rs1 +// Action: +// Rd <- Perform action encoded in OP on Rs1 +// OP is one of: +// 0b001 POPC Population count; +// 0b010 LEADZ Count number of leading zeros; +// 0b011 TRAILZ Count number of trailing zeros; +class InstSpecial op, dag outs, dag ins, string asmstr, + list pattern> : InstLanai, Sched<[WriteALU]> { + let Itinerary = IIC_ALU; + bit F; + bits<5> Rd; + bits<5> Rs1; + + let Opcode = 0b1101; + let Inst{27 - 23} = Rd; + let Inst{22 - 18} = Rs1; + let Inst{17} = F; + let Inst{16 - 3} = 0; + let Inst{2 - 0} = op; +} + +// Pseudo instructions +class Pseudo pattern> + : InstLanai { + let Inst{15 - 0} = 0; + let isPseudo = 1; +} Index: lib/Target/Lanai/LanaiInstrInfo.h =================================================================== --- lib/Target/Lanai/LanaiInstrInfo.h +++ lib/Target/Lanai/LanaiInstrInfo.h @@ -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 &Condition, + bool AllowModify) const override; + + unsigned RemoveBranch(MachineBasicBlock &MBB) const override; + + bool ReverseBranchCondition( + SmallVectorImpl &Condition) const override; + + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TrueBlock, + MachineBasicBlock *FalseBlock, + ArrayRef 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 Index: lib/Target/Lanai/LanaiInstrInfo.cpp =================================================================== --- lib/Target/Lanai/LanaiInstrInfo.cpp +++ lib/Target/Lanai/LanaiInstrInfo.cpp @@ -0,0 +1,384 @@ +//===-- 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(*this) {} + +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 &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(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 &Condition) const { + assert((Condition.size() == 1) && + "Lanai branch conditions should have one component."); + + LPCC::CondCode BranchCond = + static_cast(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 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 { +// LanaiSaveReturnAddress - Add an instruction immediately prior to +// each call instruction to save RCA (add %pc, 16, %rca). The +// Return Continuation Address (RCA) was used to store the return address but +// is currently only used as a scratch register. The current calling convention +// pushes and pops the return address from the stack with RCA used only to +// compute the return address to store. TODO: Use RCA in return. +struct LanaiSaveReturnAddress : public MachineFunctionPass { + static char Id; + LanaiSaveReturnAddress() : MachineFunctionPass(Id) {} + + bool runOnMachineFunction(MachineFunction &MF) override { + bool BlockChanged = false; + const TargetInstrInfo *InstrInfo = + MF.getSubtarget().getInstrInfo(); + for (MachineBasicBlock &block : MF) { + for (MachineInstr &MI : block) { + if (MI.getOpcode() == Lanai::CALL || MI.getOpcode() == Lanai::CALLR) { + // 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). + BuildMI(block, &MI, MI.getDebugLoc(), InstrInfo->get(Lanai::ADD_I_LO), + Lanai::RCA) + .addReg(Lanai::PC) + .addImm(16); + + // Push rca onto the stack. + // st %rca, [--%sp] + BuildMI(block, &MI, MI.getDebugLoc(), InstrInfo->get(Lanai::SW_RI)) + .addReg(Lanai::RCA) + .addReg(Lanai::SP) + .addImm(-4) + .addImm(LPAC::makePreOp(LPAC::ADD)); + + BlockChanged = true; + } + } + } + return BlockChanged; + } + + const char *getPassName() const override { + return "Lanai Save Return Address Pass"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + MachineFunctionPass::getAnalysisUsage(AU); + } +}; +} // namespace + +char LanaiSaveReturnAddress::Id = 0; +FunctionPass *createLanaiSaveReturnAddressPass() { + return new LanaiSaveReturnAddress(); +} +} // namespace llvm Index: lib/Target/Lanai/LanaiInstrInfo.td =================================================================== --- lib/Target/Lanai/LanaiInstrInfo.td +++ lib/Target/Lanai/LanaiInstrInfo.td @@ -0,0 +1,910 @@ +//===-- LanaiInstrInfo.td - Target Description for Lanai Target -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the Lanai instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction format superclass +//===----------------------------------------------------------------------===// + +include "LanaiInstrFormats.td" + +// -------------------------------------------------- // +// Instruction Operands and Patterns +// -------------------------------------------------- // + +// These are target-independent nodes, but have target-specific formats. +def SDT_LanaiCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>; +def SDT_LanaiCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, + SDTCisVT<1, i32>]>; +def SDT_LanaiCall : SDTypeProfile<0, -1, [SDTCisVT<0, i32>]>; +def SDT_LanaiSetFlag : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; +def SDT_LanaiSelectCC : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, + SDTCisSameAs<1, 2>]>; +def SDT_LanaiSetCC : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, + SDTCisVT<1, i32>]>; +def SDT_LanaiBrCC : SDTypeProfile<0, 2, [SDTCisVT<0, OtherVT>, + SDTCisVT<1, i32>]>; +def SDT_LanaiAdjDynAlloc : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, + SDTCisVT<1, i32>]>; + +def Call : SDNode<"LanaiISD::CALL", SDT_LanaiCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; +def RetFlag : SDNode<"LanaiISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; +def CallSeqStart : SDNode<"ISD::CALLSEQ_START", SDT_LanaiCallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; +def CallSeqEnd : SDNode<"ISD::CALLSEQ_END", SDT_LanaiCallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; +def LanaiSetFlag : SDNode<"LanaiISD::SET_FLAG", SDT_LanaiSetFlag, + [SDNPOutGlue]>; +def LanaiBrCC : SDNode<"LanaiISD::BR_CC", SDT_LanaiBrCC, + [SDNPHasChain, SDNPInGlue]>; +def LanaiSelectCC : SDNode<"LanaiISD::SELECT_CC", SDT_LanaiSelectCC, + [SDNPInGlue]>; +def LanaiSetCC : SDNode<"LanaiISD::SETCC", SDT_LanaiSetCC, + [SDNPInGlue]>; +def LanaiHi : SDNode<"LanaiISD::HI", SDTIntUnaryOp>; +def LanaiLo : SDNode<"LanaiISD::LO", SDTIntUnaryOp>; +def LanaiSmall : SDNode<"LanaiISD::SMALL", SDTIntUnaryOp>; +def LanaiAdjDynAlloc : SDNode<"LanaiISD::ADJDYNALLOC", SDT_LanaiAdjDynAlloc>; + +// Extract bits 0-15 (low-end) of an immediate value. +def LO16 : SDNodeXFormgetTargetConstant((uint64_t)N->getZExtValue() & 0xffff, + SDLoc(N), MVT::i32); +}]>; + +// Extract bits 16-31 (high-end) of an immediate value. +// Transformation function: shift the immediate value down into the low bits. +def HI16 : SDNodeXFormgetTargetConstant((uint64_t)N->getZExtValue() >> 16, SDLoc(N), + MVT::i32); +}]>; + +def NEG : SDNodeXFormgetTargetConstant(-N->getSExtValue(), SDLoc(N), MVT::i32); +}]>; + +def LO21 : SDNodeXFormgetTargetConstant((uint64_t)N->getZExtValue() & 0x1fffff, + SDLoc(N), MVT::i32); +}]>; + +// Branch targets +def BrTargetAsmOperand : AsmOperandClass { + let Name = "BrTarget"; +} +def BrTarget : Operand { + let ParserMatchClass = BrTargetAsmOperand; + let EncoderMethod = "getBranchTargetOpValue"; + let DecoderMethod = "decodeBranch"; +} + +def CallTargetAsmOperand : AsmOperandClass { + let Name = "CallTarget"; +} +def CallTarget : Operand { + let ParserMatchClass = CallTargetAsmOperand; + let EncoderMethod = "getBranchTargetOpValue"; + let DecoderMethod = "decodeBranch"; +} + +def Imm6AsmOperand : AsmOperandClass { let Name = "Imm6"; } +def immZExt6 : Operand, PatLeaf<(imm), [{ + return N->getZExtValue() > 0 && isInt<6>(N->getZExtValue()); }]> { + let ParserMatchClass = Imm6AsmOperand; +} + +def Imm6NegAsmOperand : AsmOperandClass { let Name = "NegImm6"; } +def immNegZExt6 : Operand, PatLeaf<(imm), [{ + return isInt<6>(N->getZExtValue()); }]> { + let ParserMatchClass = Imm6NegAsmOperand; + let EncoderMethod = "getNeg6OpValue"; + let DecoderMethod = "decodeNeg6OpValue"; + let PrintMethod = "printNeg6ImmOperand"; +} + +def Imm10AsmOperand : AsmOperandClass { let Name = "Imm10"; } +def imm10 : Operand, PatLeaf<(imm), [{ + return isInt<10>(N->getSExtValue()); }]> { + let ParserMatchClass = Imm10AsmOperand; +} + +def immZExt21 : PatLeaf<(imm), + [{return isUInt<21>(N->getZExtValue()); }], LO21>; + +def LoImm16AsmOperand : AsmOperandClass { let Name = "LoImm16"; } +def i32lo16z : Operand, PatLeaf<(i32 imm), [{ + // i32lo16 predicate - true if the 32-bit immediate has only rightmost 16 + // bits set. + return ((N->getZExtValue() & 0xFFFFUL) == N->getZExtValue());}], LO16> { + let ParserMatchClass = LoImm16AsmOperand; +} +def i32neg16 : Operand, PatLeaf<(i32 imm), [{ + // i32neg16 predicate - true if the 32-bit immediate is negative and can + // be represented by a 16 bit integer. + int value = N->getSExtValue(); + return (value < 0) && (isInt<16>(value));}], LO16> { + let ParserMatchClass = LoImm16AsmOperand; +} +def i32lo16s : Operand, PatLeaf<(i32 imm), [{ + // i32lo16 predicate - true if the 32-bit immediate has only rightmost 16 + // bits set. + return ((N->getSExtValue() & 0xFFFFUL) == N->getSExtValue());}], LO16> { + let ParserMatchClass = LoImm16AsmOperand; +} + +def LoImm16AndAsmOperand : AsmOperandClass { let Name = "LoImm16And"; } +def i32lo16and : Operand, PatLeaf<(i32 imm), [{ + // i32lo16 predicate - true if the 32-bit immediate has the rightmost 16 + // bits set and the leftmost 16 bits 1's. + return (N->getZExtValue() >= 0xFFFF0000UL);}], LO16> { + let ParserMatchClass = LoImm16AndAsmOperand; + let PrintMethod = "printLo16AndImmOperand"; +} + +def HiImm16AsmOperand : AsmOperandClass { let Name = "HiImm16"; } +def i32hi16 : Operand, PatLeaf<(i32 imm), [{ + // i32hi16 predicate - true if the 32-bit immediate has only leftmost 16 + // bits set. + return ((N->getZExtValue() & 0xFFFF0000UL) == N->getZExtValue());}], HI16> { + let ParserMatchClass = HiImm16AsmOperand; + let PrintMethod = "printHi16ImmOperand"; +} + +def HiImm16AndAsmOperand : AsmOperandClass { let Name = "HiImm16And"; } +def i32hi16and : Operand, PatLeaf<(i32 imm), [{ + // i32lo16 predicate - true if the 32-bit immediate has the leftmost 16 + // bits set and the rightmost 16 bits 1's. + return ((N->getZExtValue() & 0xFFFFUL) == 0xFFFFUL);}], HI16> { + let ParserMatchClass = HiImm16AndAsmOperand; + let PrintMethod = "printHi16AndImmOperand"; +} + +def LoImm21AsmOperand : AsmOperandClass { let Name = "LoImm21"; } +def i32lo21 : Operand, PatLeaf<(i32 imm), [{ + // i32lo21 predicate - true if the 32-bit immediate has only rightmost 21 + // bits set. + return ((N->getZExtValue() & 0x1FFFFFUL) == N->getZExtValue());}], LO21> { + let ParserMatchClass = LoImm21AsmOperand; +} + +def AluOp : Operand { + let PrintMethod = "printAluOperand"; +} + +// Addressing modes. +def ADDRrr : ComplexPattern; +def ADDRri : ComplexPattern; +def ADDRsls : ComplexPattern; +def ADDRspls : ComplexPattern; + +// Address operands +def MemRegImmAsmOperand : AsmOperandClass { + let Name = "MemRegImm"; + let ParserMethod = "parseMemoryOperand"; +} +def MEMri : Operand { + let DecoderMethod = "decodeRiMemoryValue"; + let EncoderMethod = "getRiMemoryOpValue"; + let MIOperandInfo = (ops GPR:$base, i32lo16s:$offset, AluOp:$Opcode); + let ParserMatchClass = MemRegImmAsmOperand; + let PrintMethod = "printMemRiOperand"; +} + +def MemRegRegAsmOperand : AsmOperandClass { + let Name = "MemRegReg"; + let ParserMethod = "parseMemoryOperand"; +} +def MEMrr : Operand { + let DecoderMethod = "decodeRrMemoryValue"; + let EncoderMethod = "getRrMemoryOpValue"; + let MIOperandInfo = (ops GPR:$Op1, GPR:$Op2, AluOp:$Opcode); + let ParserMatchClass = MemRegRegAsmOperand; + let PrintMethod = "printMemRrOperand"; +} + +def MemImmAsmOperand : AsmOperandClass { + let Name = "MemImm"; + let ParserMethod = "parseMemoryOperand"; +} +def MEMi : Operand { + let MIOperandInfo = (ops i32lo21:$offset); + let ParserMatchClass = MemImmAsmOperand; + let PrintMethod = "printMemImmOperand"; +} + +def MemSplsAsmOperand : AsmOperandClass { + let Name = "MemSpls"; + let ParserMethod = "parseMemoryOperand"; +} +def MEMspls : Operand { + let DecoderMethod = "decodeSplsValue"; + let EncoderMethod = "getSplsOpValue"; + let MIOperandInfo = (ops GPR:$base, imm10:$offset, AluOp:$Opcode); + let ParserMatchClass = MemSplsAsmOperand; + let PrintMethod = "printMemSplsOperand"; +} + +def CCOp : Operand { + let PrintMethod = "printCCOperand"; +} + +let hasSideEffects = 0, Inst = 0x00000001 in + def NOP : InstLanai<(outs), (ins), "nop", []>; + +// Special NOPs to change logging level in vlanai. +let hasSideEffects = 0, Inst = 0x00000002 in + def LOG0 : InstLanai<(outs), (ins), "log_0", []>; +let hasSideEffects = 0, Inst = 0x00000003 in + def LOG1 : InstLanai<(outs), (ins), "log_1", []>; +let hasSideEffects = 0, Inst = 0x00000004 in + def LOG2 : InstLanai<(outs), (ins), "log_2", []>; +let hasSideEffects = 0, Inst = 0x00000005 in + def LOG3 : InstLanai<(outs), (ins), "log_3", []>; +let hasSideEffects = 0, Inst = 0x00000006 in + def LOG4 : InstLanai<(outs), (ins), "log_4", []>; + +// Map an SPLS instruction onto itself. All other instructions will be mapped +// onto -1. Used to identify SPLS instructions. +def splsIdempotent : InstrMapping { + let FilterClass = "InstSPLS"; + let RowFields = ["AsmString"]; + let ColFields = ["PostEncoderMethod"]; + let KeyCol = ["adjustPqBitsSpls"]; + let ValueCols = [["adjustPqBitsSpls"]]; +} + +// -------------------------------------------------- // +// ALU instructions +// -------------------------------------------------- // +multiclass ALUbase subOp, string AsmStr, SDNode OpNode, + PatLeaf LoExt, PatLeaf HiExt, + list loPattern, list hiPattern> { + // Register Immediate + let H = 0 in + def LO : InstRI; + let H = 1 in + def HI : InstRI; + +} + +multiclass ALUarith subOp, string AsmStr, SDNode OpNode, + PatLeaf LoExt, PatLeaf HiExt> { + defm I_ : ALUbase; + + // Register Register + let JJJJJ = 0, DDDI = 0 in + def R : InstRR; + // RR Conditional + let JJJJJ = 0, Uses = [SR] in + def R_CC : InstRR; +} + +multiclass ALUlogic subOp, string AsmStr, SDNode OpNode, + PatLeaf LoExt, PatLeaf HiExt> { + defm I_ : ALUbase; + + // Register Register + let JJJJJ = 0, DDDI = 0 in + def R : InstRR; + // RR Conditional + let JJJJJ = 0, Uses = [SR] in + def R_CC : InstRR; +} + +// Non flag setting ALU operations +let isAsCheapAsAMove = 1, F = 0 in { + let isCommutable = 1 in { + defm ADD_ : ALUarith<0b000, "add", add, i32lo16s, i32hi16>; + } + defm SUB_ : ALUarith<0b010, "sub", sub, i32lo16s, i32hi16>; + let isCommutable = 1 in { + defm AND_ : ALUlogic<0b100, "and", and, i32lo16and, i32hi16and>; + defm OR_ : ALUlogic<0b101, "or", or, i32lo16z, i32hi16>; + defm XOR_ : ALUlogic<0b110, "xor", xor, i32lo16s, i32hi16>; + } +} + +def : Pat<(add GPR:$Rs1, i32lo16z:$imm), + (ADD_I_LO GPR:$Rs1, i32lo16z:$imm)>; + +def : Pat<(sub GPR:$Rs1, i32lo16z:$imm), + (SUB_I_LO GPR:$Rs1, i32lo16z:$imm)>; + +def : Pat<(add GPR:$Rs1, i32hi16:$imm), + (ADD_I_HI GPR:$Rs1, i32hi16:$imm)>; + +def : Pat<(sub GPR:$Rs1, i32hi16:$imm), + (SUB_I_HI GPR:$Rs1, i32hi16:$imm)>; + +def : Pat<(i32 i32lo16and:$imm), (AND_I_LO (i32 R1), i32lo16and:$imm)>; +def : Pat<(i32 i32hi16and:$imm), (AND_I_HI (i32 R1), i32hi16and:$imm)>; + +// Change add/sub with negative number to sub/add +def : Pat<(add GPR:$Rs1, i32neg16:$imm), + (SUB_I_LO GPR:$Rs1, (NEG $imm))>; +def : Pat<(sub GPR:$Rs1, i32neg16:$imm), + (ADD_I_LO GPR:$Rs1, (NEG $imm))>; + +// Flag (incl. carry) setting addition and subtraction +let F = 1, Defs = [SR] in { + defm ADD_F_ : ALUarith<0b000, "add.f", addc, i32lo16s, i32hi16>; + defm SUB_F_ : ALUarith<0b010, "sub.f", subc, i32lo16s, i32hi16>; +} + +def : Pat<(addc GPR:$Rs1, i32lo16z:$imm), + (ADD_F_I_LO GPR:$Rs1, i32lo16z:$imm)>; + +def : Pat<(subc GPR:$Rs1, i32lo16z:$imm), + (SUB_F_I_LO GPR:$Rs1, i32lo16z:$imm)>; + +def : Pat<(addc GPR:$Rs1, i32hi16:$imm), + (ADD_F_I_HI GPR:$Rs1, i32hi16:$imm)>; + +def : Pat<(subc GPR:$Rs1, i32hi16:$imm), + (SUB_F_I_HI GPR:$Rs1, i32hi16:$imm)>; + +// Carry using addition and subtraction +let F = 0, Uses = [SR] in { + defm ADDC_ : ALUarith<0b001, "addc", adde, i32lo16s, i32hi16>; + defm SUBB_ : ALUarith<0b011, "subb", sube, i32lo16s, i32hi16>; +} + +def : Pat<(adde GPR:$Rs1, i32lo16z:$imm), + (ADDC_I_LO GPR:$Rs1, i32lo16z:$imm)>; + +def : Pat<(sube GPR:$Rs1, i32lo16z:$imm), + (SUBB_I_LO GPR:$Rs1, i32lo16z:$imm)>; + +def : Pat<(adde GPR:$Rs1, i32hi16:$imm), + (ADDC_I_HI GPR:$Rs1, i32hi16:$imm)>; + +def : Pat<(sube GPR:$Rs1, i32hi16:$imm), + (SUBB_I_HI GPR:$Rs1, i32hi16:$imm)>; + +// Flag setting ALU operations +let isAsCheapAsAMove = 1, F = 1, Defs = [SR] in { + defm ADDC_F_ : ALUarith<0b001, "addc.f", adde, i32lo16s, i32hi16>; + defm SUBB_F_ : ALUarith<0b011, "subb.f", sube, i32lo16s, i32hi16>; + let isCommutable = 1 in { + defm AND_F_ : ALUlogic<0b100, "and.f", and, i32lo16and, i32hi16and>; + defm OR_F_ : ALUlogic<0b101, "or.f", or, i32lo16z, i32hi16>; + defm XOR_F_ : ALUlogic<0b110, "xor.f", xor, i32lo16s, i32hi16>; + } +} + +def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0)>; + +let isAsCheapAsAMove = 1, Rs1 = R0.Num, isCodeGenOnly = 1, H = 1, F = 0, + isReMaterializable = 1 in + def MOVHI : InstRI<0b000, (outs GPR:$Rd), (ins i32hi16:$imm16), + "mov\t$imm16, $Rd", + [(set GPR:$Rd, i32hi16:$imm16)]>; + +def : InstAlias<"mov $imm16, $dst", (ADD_I_LO GPR:$dst, R0, i32lo16s:$imm16)>; +def : InstAlias<"mov $imm16, $dst", (ADD_I_HI GPR:$dst, R0, i32hi16:$imm16)>; +def : InstAlias<"mov $imm16, $dst", + (AND_I_LO GPR:$dst, R1, i32lo16and:$imm16)>; +def : InstAlias<"mov $imm16, $dst", + (AND_I_HI GPR:$dst, R1, i32hi16and:$imm16)>; + +// Shift instructions +class ShiftRI + : InstRI<0b111, (outs GPR:$Rd), (ins GPR:$Rs1, Ext:$imm16), + !strconcat(AsmStr, "\t$Rs1, $imm16, $Rd"), + [(set GPR:$Rd, (OpNode GPR:$Rs1, Ext:$imm16))]> { + let Inst{15} = b15; + let isReMaterializable = 1; +} + +let F = 0 in { + let H = 0 in + def SHL_I : ShiftRI<"sh", 0, shl, immZExt6>; + let H = 1 in + def SHA_I : ShiftRI<"sha", 0, shl, immZExt6>; + let H = 0 in + def SRL_I : ShiftRI<"sh", 1, srl, immNegZExt6>; + let H = 1 in + def SRA_I : ShiftRI<"sha", 1, sra, immNegZExt6>; +} + +// Shift with F set are not matched but just added for generation from assembly +class ShiftRIf : InstRI<0b111, + (outs GPR:$Rd), (ins GPR:$Rs1, Ext:$imm16), + !strconcat(AsmStr, ".f\t$Rs1, $imm16, $Rd"), []> { + let Inst{15} = b15; +} + +let F = 1, Defs = [SR] in { + let H = 0 in + def SHL_F_I : ShiftRIf<"sh", 0, immZExt6>; + let H = 1 in + def SHA_F_I : ShiftRIf<"sha", 0, immZExt6>; + let H = 0 in + def SRL_F_I : ShiftRIf<"sh", 1, immNegZExt6>; + let H = 1 in + def SRA_F_I : ShiftRIf<"sha", 1, immNegZExt6>; +} + +class ShiftRR Pattern> + : InstRR<0b111, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2), AsmStr, Pattern> { + let DDDI = 0; +} + +let F = 0 in { + let JJJJJ = 0b10000 in + def SHL_R : ShiftRR<"sh\t$Rs1, $Rs2, $Rd", + [(set GPR:$Rd, (shl GPR:$Rs1, GPR:$Rs2))]>; + let isCodeGenOnly = 1 in { + let JJJJJ = 0b10000 in + def SRL_R : ShiftRR<"sh\t$Rs1, $Rs2, $Rd", []>; + } + let JJJJJ = 0b11000 in + def SRA_R : ShiftRR<"sha\t$Rs1, $Rs2, $Rd", []>; +} + +let F = 1, Defs = [SR] in { + let JJJJJ = 0b10000 in + def SHL_F_R : ShiftRR<"sh.f\t$Rs1, $Rs2, $Rd", []>; + let isCodeGenOnly = 1 in { + let JJJJJ = 0b10000 in + def SRL_F_R : ShiftRR<"sh.f\t$Rs1, $Rs2, $Rd", []>; + } + let JJJJJ = 0b11000 in + def SRA_F_R : ShiftRR<"sha.f\t$Rs1, $Rs2, $Rd", []>; +} + +// Expand shift-right operations +def : Pat<(srl GPR:$Rs1, GPR:$Rs2), + (SRL_R GPR:$Rs1, (SUB_R R0, GPR:$Rs2))>; +def : Pat<(sra GPR:$Rs1, GPR:$Rs2), + (SRA_R GPR:$Rs1, (SUB_R R0, GPR:$Rs2))>; + +// -------------------------------------------------- // +// LOAD instructions +// -------------------------------------------------- // + +class LoadRR + : InstRRM<0b0, (outs GPR:$Rd), (ins MEMrr:$src), + !strconcat(OpcString, "\t$src, $Rd"), + [(set (Ty GPR:$Rd), (OpNode ADDRrr:$src))]>, + Sched<[WriteLD]> { + bits<20> src; + + let Rs1 = src{19-15}; + let Rs2 = src{14-10}; + let P = src{9}; + let Q = src{8}; + let BBB = src{7-5}; + let JJJJJ = src{4-0}; +} + +class LoadRI + : InstRM<0b0, (outs GPR:$Rd), (ins MEMri:$src), + !strconcat(OpcString, "\t$src, $Rd"), + [(set (Ty GPR:$Rd), (OpNode ADDRri:$src))]>, + Sched<[WriteLD]> { + bits<23> src; + + let Itinerary = IIC_LD; + let Rs1 = src{22-18}; + let P = src{17}; + let Q = src{16}; + let imm16 = src{15-0}; + let isReMaterializable = 1; +} + +let E = 0 in { + let YL = 0b01 in { + // uld is used here and ld in the alias as the alias is printed out first if + // an alias exist + def LDW_RI : LoadRI<"uld", load, i32>; + def LDW_RR : LoadRR<"ld", load, i32>; + } +} + +def : InstAlias<"ld $src, $dst", (LDW_RI GPR:$dst, MEMri:$src)>; + +let E = 1 in { + let YL = 0b01 in { + def LDWz_RR : LoadRR<"uld", zextloadi32, i32>; + } +} + +let E = 1 in { + let YL = 0b00 in + def LDHz_RR : LoadRR<"uld.h", zextloadi16, i32>; + let YL = 0b10 in + def LDBz_RR : LoadRR<"uld.b", zextloadi8, i32>; +} + +let E = 0 in { + let YL = 0b00 in + def LDHs_RR : LoadRR<"ld.h", sextloadi16, i32>; + let YL = 0b10 in + def LDBs_RR : LoadRR<"ld.b", sextloadi8, i32>; +} + +def LDADDR : InstSLS<0x0, (outs GPR:$Rd), (ins MEMi:$src), + "ld\t$src, $Rd", + [(set (i32 GPR:$Rd), (load ADDRsls:$src))]>, + Sched<[WriteLD]> { + bits<21> src; + + let Itinerary = IIC_LD; + let msb = src{20-16}; + let lsb = src{15-0}; + let isReMaterializable = 1; +} + +class LoadSPLS + : InstSPLS<(outs GPR:$Rd), (ins MEMspls:$src), + !strconcat(asmstring, "\t$src, $Rd"), + [(set (i32 GPR:$Rd), (opNode ADDRspls:$src))]>, + Sched<[WriteLD]> { + bits<17> src; + let Itinerary = IIC_LD; + let Rs1 = src{16-12}; + let P = src{11}; + let Q = src{10}; + let imm10 = src{9-0}; +} + +let Y = 0, S = 0, E = 1 in + def LDHz_RI : LoadSPLS<"uld.h", zextloadi16>; + +let Y = 0, S = 0, E = 0 in + def LDHs_RI : LoadSPLS<"ld.h", sextloadi16>; + +let Y = 1, S = 0, E = 1 in + def LDBz_RI : LoadSPLS<"uld.b", zextloadi8>; + +let Y = 1, S = 0, E = 0 in + def LDBs_RI : LoadSPLS<"ld.b", sextloadi8>; + +def SLI : InstSLI<(outs GPR:$Rd), (ins i32lo21:$imm), + "mov\t$imm, $Rd", + [(set GPR:$Rd, i32lo21:$imm)]> { + bits<21> imm; + + let Itinerary = IIC_LD; + let msb = imm{20-16}; + let lsb = imm{15-0}; + let isReMaterializable = 1; +} + +// -------------------------------------------------- // +// STORE instructions +// -------------------------------------------------- // + +class StoreRR + : InstRRM<0b1, (outs), (ins GPR:$Rd, MEMrr:$dst), + !strconcat(OpcString, "\t$Rd, $dst"), + [(OpNode (Ty GPR:$Rd), ADDRrr:$dst)]>, + Sched<[WriteST]> { + bits<20> dst; + + let Itinerary = IIC_ST; + let Rs1 = dst{19-15}; + let Rs2 = dst{14-10}; + let P = dst{9}; + let Q = dst{8}; + let BBB = dst{7-5}; + let JJJJJ = dst{4-0}; +} + +class StoreRI + : InstRM<0b1, (outs), (ins GPR:$Rd, MEMri:$dst), + !strconcat(OpcString, "\t$Rd, $dst"), + [(OpNode (Ty GPR:$Rd), ADDRri:$dst)]>, + Sched<[WriteST]> { + bits<23> dst; + + let Itinerary = IIC_ST; + let Rs1 = dst{22-18}; + let P = dst{17}; + let Q = dst{16}; + let imm16 = dst{15-0}; +} + +let YL = 0b01, E = 0 in { + def SW_RR : StoreRR<"st", store, i32>; + def SW_RI : StoreRI<"st", store, i32>; +} + +let E = 0 in { + let YL = 0b00 in + def STH_RR : StoreRR<"st.h", truncstorei16, i32>; + let YL = 0b10 in + def STB_RR : StoreRR<"st.b", truncstorei8, i32>; +} + +def STADDR : InstSLS<0x1, (outs), (ins GPR:$Rd, MEMi:$dst), + "st\t$Rd, $dst", + [(store (i32 GPR:$Rd), ADDRsls:$dst)]>, + Sched<[WriteST]> { + bits<21> dst; + + let Itinerary = IIC_ST; + let msb = dst{20-16}; + let lsb = dst{15-0}; +} + +class StoreSPLS + : InstSPLS<(outs), (ins GPR:$Rd, MEMspls:$dst), + !strconcat(asmstring, "\t$Rd, $dst"), + [(opNode (i32 GPR:$Rd), ADDRspls:$dst)]>, + Sched<[WriteST]> { + bits<17> dst; + + let Itinerary = IIC_ST; + let Rs1 = dst{16-12}; + let P = dst{11}; + let Q = dst{10}; + let imm10 = dst{9-0}; +} + +let Y = 0, S = 1, E = 0 in + def STH_RI : StoreSPLS<"st.h", truncstorei16>; + +let Y = 1, S = 1, E = 0 in + def STB_RI : StoreSPLS<"st.b", truncstorei8>; + +// -------------------------------------------------- // +// BRANCH instructions +// -------------------------------------------------- // + +let isBranch = 1, isBarrier = 1, isTerminator = 1, hasDelaySlot = 1 in { + def BT : InstBR<(outs), (ins BrTarget:$addr), + "bt\t$addr", + [(br bb:$addr)]> { + let DDDI = 0b0000; + } + let Uses = [SR] in + def BRCC : InstBR<(outs), (ins BrTarget:$addr, CCOp:$DDDI), + "b$DDDI\t$addr", + [(LanaiBrCC bb:$addr, imm:$DDDI)]>; + + let isIndirectBranch = 1 in { + def JR : InstRR<0b101, (outs), (ins GPR:$Rs2), "bt\t$Rs2", + [(brind GPR:$Rs2)]> { + let Rs1 = R0.Num; + let Rd = R2.Num; + let F = 0; + let JJJJJ = 0; + let DDDI = 0; + } + } +} + +// -------------------------------------------------- // +// Condition/SF instructions +// -------------------------------------------------- // + +// Instructions to set flags used in lowering comparisons. +multiclass SF op2Val, string AsmStr> { + let F = 1, Rd = R0.Num, JJJJJ = 0, Defs = [SR], DDDI = 0 in + def _RR : InstRR; + let F = 1, Rd = R0.Num, H = 0, Defs = [SR] in + def _RI : InstRI; +} +let isCodeGenOnly = 1 in { + defm SFSUB_F : SF<0b010, "sub.f">; +} + +// Jump and link +let isCall = 1, hasDelaySlot = 1, isCodeGenOnly = 1, Uses = [SP] in { + def CALL : InstBR<(outs), (ins CallTarget:$addr), "bt\t$addr", []> { + let DDDI = 0b0000; + } + def CALLR : InstRR<0b000, (outs), (ins GPR:$Rs1), "bt\t$Rs1", + [(Call GPR:$Rs1)]> { + let Rd = PC.Num; + let Rs2 = R0.Num; + let F = 0; + let JJJJJ = 0; + let DDDI = 0; + } +} + +let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in { + def RET : InstRM<0b0, (outs), (ins), + "ld\t-4[%fp], %pc ! return", + [(RetFlag)]> { + let Rd = PC.Num; + let Rs1 = FP.Num; + let P = 1; + let Q = 0; + let imm16 = -4; + + // Post encoding is not needed for RET. + let PostEncoderMethod = ""; + } +} + +// ADJCALLSTACKDOWN/UP implicitly use/def SP because they may be expanded into +// a stack adjustment and the codegen must know that they may modify the stack +// pointer before prolog-epilog rewriting occurs. +// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become +// sub / add which can clobber SP. +let Defs = [SP], Uses = [SP] in { + def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt), + "#ADJCALLSTACKDOWN $amt", + [(CallSeqStart timm:$amt)]>; + def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), + "#ADJCALLSTACKUP $amt1 $amt2", + [(CallSeqEnd timm:$amt1, timm:$amt2)]>; +} + +let Defs = [SP], Uses = [SP] in { + def ADJDYNALLOC : Pseudo<(outs GPR:$dst), (ins GPR:$src), + "#ADJDYNALLOC $dst $src", + [(set GPR:$dst, (LanaiAdjDynAlloc GPR:$src))]>; +} + +let Uses = [SR] in { + def SCC : InstSCC<(outs GPR:$Rs1), (ins CCOp:$DDDI), + "s$DDDI\t$Rs1", + [(set (i32 GPR:$Rs1), (LanaiSetCC imm:$DDDI))]>; +} + +// SCC's output is already 1-bit so and'ing with 1 is redundant. +def : Pat<(and (LanaiSetCC imm:$DDDI), 1), (SCC imm:$DDDI)>; + +// Select with hardware support +let Uses = [SR], isSelect = 1 in { + def SELECT : InstRR<0b111, (outs GPR:$Rd), + (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI), + "sel.$DDDI $Rs1, $Rs2, $Rd", + [(set (i32 GPR:$Rd), + (LanaiSelectCC (i32 GPR:$Rs1), (i32 GPR:$Rs2), + (imm:$DDDI)))]> { + let JJJJJ = 0; + let F = 0; + } +} + +let isBranch = 1, isBarrier = 1, isTerminator = 1, hasDelaySlot = 1, + isIndirectBranch = 1, Uses = [SR] in { + def BRIND_CC : InstRR<0b101, (outs), (ins GPR:$Rs1, CCOp:$DDDI), + "b$DDDI\t$Rs1", []> { + let F = 0; + let JJJJJ = 0; + let Rd = PC.Num; + let Rs2 = R0.Num; + } + + def BRIND_CCA : InstRR<0b101, (outs), (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI), + "b${DDDI}\t$Rs1 add $Rs2", []> { + let F = 0; + let Rd = PC.Num; + let JJJJJ = 0; + } +} + +// TODO: This only considers the case where BROFF is an immediate and not where +// it is a register. Add support for register relative branching. +let isBranch = 1, isBarrier = 1, isTerminator = 1, hasDelaySlot = 1, Rs1 = 0, + Uses = [SR] in + def BRR : InstBRR<(outs), (ins i16imm:$imm16, CCOp:$DDDI), + "b${DDDI}.r\t$imm16", []>; + +let F = 0 in { +// Population Count (POPC) +def POPC: InstSpecial<0b001, (outs GPR:$Rd), (ins GPR:$Rs1), + "popc\t$Rs1, $Rd", + [(set GPR:$Rd, (ctpop GPR:$Rs1))]>; + +// Count Leading Zeros (LEADZ) +def LEADZ: InstSpecial<0b010, (outs GPR:$Rd), (ins GPR:$Rs1), + "leadz\t$Rs1, $Rd", [(set GPR:$Rd, (ctlz GPR:$Rs1))]>; +let isCodeGenOnly = 1 in + def LEADZUNDEF: InstSpecial<0b010, (outs GPR:$Rd), (ins GPR:$Rs1), + "leadz\t$Rs1, $Rd", + [(set GPR:$Rd, (ctlz_zero_undef GPR:$Rs1))]>; + +// Count Trailing Zeros (TRAILZ) +def TRAILZ : InstSpecial<0b011, (outs GPR:$Rd), (ins GPR:$Rs1), + "trailz\t$Rs1, $Rd", + [(set GPR:$Rd, (cttz GPR:$Rs1))]>; +let isCodeGenOnly = 1 in + def TRAILZUNDEF : InstSpecial<0b011, (outs GPR:$Rd), (ins GPR:$Rs1), + "trailz\t$Rs1, $Rd", + [(set GPR:$Rd, + (cttz_zero_undef GPR:$Rs1))]>; +} + +//===----------------------------------------------------------------------===// +// Non-Instruction Patterns +//===----------------------------------------------------------------------===// + +// signed 16-bit immediate +def : Pat<(i32 i32lo16s:$imm), (MOVHI imm:$imm)>; + +// i32 0 and R0 can be used interchangeably. +def : Pat<(i32 0), (i32 R0)>; +// i32 -1 and R1 can be used interchangeably. +def : Pat<(i32 -1), (i32 R1)>; + +// unsigned 16-bit immediate +def : Pat<(i32 i32lo16z:$imm), (OR_I_LO (i32 R0), imm:$imm)>; + +// arbitrary immediate +def : Pat<(i32 imm:$imm), (OR_I_LO (MOVHI (HI16 imm:$imm)), (LO16 imm:$imm))>; + +// Calls +def : Pat<(Call tglobaladdr:$dst), (CALL tglobaladdr:$dst)>; +def : Pat<(Call texternalsym:$dst), (CALL texternalsym:$dst)>; + +// Loads +def : Pat<(extloadi8 ADDRspls:$src), (i32 (LDBz_RI ADDRspls:$src))>; +def : Pat<(extloadi16 ADDRspls:$src), (i32 (LDHz_RI ADDRspls:$src))>; + +// GlobalAddress, ExternalSymbol, Jumptable, ConstantPool +def : Pat<(LanaiHi tglobaladdr:$dst), (MOVHI tglobaladdr:$dst)>; +def : Pat<(LanaiLo tglobaladdr:$dst), (OR_I_LO (i32 R0), tglobaladdr:$dst)>; +def : Pat<(LanaiSmall tglobaladdr:$dst), (SLI tglobaladdr:$dst)>; +def : Pat<(LanaiHi texternalsym:$dst), (MOVHI texternalsym:$dst)>; +def : Pat<(LanaiLo texternalsym:$dst), (OR_I_LO (i32 R0), texternalsym:$dst)>; +def : Pat<(LanaiSmall texternalsym:$dst), (SLI texternalsym:$dst)>; +def : Pat<(LanaiHi tblockaddress:$dst), (MOVHI tblockaddress:$dst)>; +def : Pat<(LanaiLo tblockaddress:$dst), (OR_I_LO (i32 R0), tblockaddress:$dst)>; +def : Pat<(LanaiSmall tblockaddress:$dst), (SLI tblockaddress:$dst)>; +def : Pat<(LanaiHi tjumptable:$dst), (MOVHI tjumptable:$dst)>; +def : Pat<(LanaiLo tjumptable:$dst), (OR_I_LO (i32 R0), tjumptable:$dst)>; +def : Pat<(LanaiSmall tjumptable:$dst), (SLI tjumptable:$dst)>; +def : Pat<(LanaiHi tconstpool:$dst), (MOVHI tconstpool:$dst)>; +def : Pat<(LanaiLo tconstpool:$dst), (OR_I_LO (i32 R0), tconstpool:$dst)>; +def : Pat<(LanaiSmall tconstpool:$dst), (SLI tconstpool:$dst)>; + +def : Pat<(or GPR:$hi, (LanaiLo tglobaladdr:$lo)), + (OR_I_LO GPR:$hi, tglobaladdr:$lo)>; +def : Pat<(or R0, (LanaiSmall tglobaladdr:$small)), + (SLI tglobaladdr:$small)>; +def : Pat<(or GPR:$hi, (LanaiLo texternalsym:$lo)), + (OR_I_LO GPR:$hi, texternalsym:$lo)>; +def : Pat<(or R0, (LanaiSmall texternalsym:$small)), + (SLI texternalsym:$small)>; +def : Pat<(or GPR:$hi, (LanaiLo tblockaddress:$lo)), + (OR_I_LO GPR:$hi, tblockaddress:$lo)>; +def : Pat<(or R0, (LanaiSmall tblockaddress:$small)), + (SLI tblockaddress:$small)>; +def : Pat<(or GPR:$hi, (LanaiLo tjumptable:$lo)), + (OR_I_LO GPR:$hi, tjumptable:$lo)>; +def : Pat<(or R0, (LanaiSmall tjumptable:$small)), + (SLI tjumptable:$small)>; +def : Pat<(or GPR:$hi, (LanaiLo tconstpool:$lo)), + (OR_I_LO GPR:$hi, tconstpool:$lo)>; +def : Pat<(or R0, (LanaiSmall tconstpool:$small)), + (SLI tconstpool:$small)>; Index: lib/Target/Lanai/LanaiMCInstLower.h =================================================================== --- lib/Target/Lanai/LanaiMCInstLower.h +++ lib/Target/Lanai/LanaiMCInstLower.h @@ -0,0 +1,48 @@ +//===-- LanaiMCInstLower.h - Lower MachineInstr to MCInst -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_LANAIMCINSTLOWER_H +#define LLVM_LIB_TARGET_LANAI_LANAIMCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { +class AsmPrinter; +class MCContext; +class MCInst; +class MCOperand; +class MCSymbol; +class MachineInstr; +class MachineModuleInfoMachO; +class MachineOperand; +class Mangler; + +// LanaiMCInstLower - This class is used to lower an MachineInstr +// into an MCInst. +class LLVM_LIBRARY_VISIBILITY LanaiMCInstLower { + MCContext &Ctx; + + AsmPrinter &Printer; + +public: + LanaiMCInstLower(MCContext &CTX, Mangler &Mang, AsmPrinter &AP) + : Ctx(CTX), Printer(AP) {} + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetBlockAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_LANAIMCINSTLOWER_H Index: lib/Target/Lanai/LanaiMCInstLower.cpp =================================================================== --- lib/Target/Lanai/LanaiMCInstLower.cpp +++ lib/Target/Lanai/LanaiMCInstLower.cpp @@ -0,0 +1,139 @@ +//=-- LanaiMCInstLower.cpp - Convert Lanai MachineInstr to an MCInst --------=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower Lanai MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "LanaiMCInstLower.h" + +#include "MCTargetDesc/LanaiBaseInfo.h" +#include "MCTargetDesc/LanaiMCExpr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Mangler.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +MCSymbol * +LanaiMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { + return Printer.getSymbol(MO.getGlobal()); +} + +MCSymbol * +LanaiMCInstLower::GetBlockAddressSymbol(const MachineOperand &MO) const { + return Printer.GetBlockAddressSymbol(MO.getBlockAddress()); +} + +MCSymbol * +LanaiMCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const { + return Printer.GetExternalSymbolSymbol(MO.getSymbolName()); +} + +MCSymbol *LanaiMCInstLower::GetJumpTableSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + // Create a symbol for the name. + return Ctx.getOrCreateSymbol(Name.str()); +} + +MCSymbol * +LanaiMCInstLower::GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + // Create a symbol for the name. + return Ctx.getOrCreateSymbol(Name.str()); +} + +MCOperand LanaiMCInstLower::LowerSymbolOperand(const MachineOperand &MO, + MCSymbol *Sym) const { + LanaiMCExpr::VariantKind Kind; + + switch (MO.getTargetFlags()) { + case LanaiII::MO_NO_FLAG: + Kind = LanaiMCExpr::VK_Lanai_None; + break; + case LanaiII::MO_ABS_HI: + Kind = LanaiMCExpr::VK_Lanai_ABS_HI; + break; + case LanaiII::MO_ABS_LO: + Kind = LanaiMCExpr::VK_Lanai_ABS_LO; + break; + default: + llvm_unreachable("Unknown target flag on GV operand"); + } + + const MCSymbolRefExpr *Symbol = MCSymbolRefExpr::create(Sym, Ctx); + const MCExpr *Expr = LanaiMCExpr::create(Kind, Symbol, Ctx); + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::createAdd( + Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); + return MCOperand::createExpr(Expr); +} + +void LanaiMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) { + const MachineOperand &MO = MI->getOperand(I); + + MCOperand MCOp; + switch (MO.getType()) { + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) + continue; + MCOp = MCOperand::createReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::createImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::createExpr( + MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx)); + break; + case MachineOperand::MO_RegisterMask: + continue; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_BlockAddress: + MCOp = LowerSymbolOperand(MO, GetBlockAddressSymbol(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); + break; + default: + MI->dump(); + llvm_unreachable("unknown operand type"); + } + + OutMI.addOperand(MCOp); + } +} Index: lib/Target/Lanai/LanaiMachineFunctionInfo.h =================================================================== --- lib/Target/Lanai/LanaiMachineFunctionInfo.h +++ lib/Target/Lanai/LanaiMachineFunctionInfo.h @@ -0,0 +1,58 @@ +//===- LanaiMachineFuctionInfo.h - Lanai machine func info -------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares Lanai-specific per-machine-function information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_LANAIMACHINEFUNCTIONINFO_H +#define LLVM_LIB_TARGET_LANAI_LANAIMACHINEFUNCTIONINFO_H + +#include "LanaiRegisterInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +namespace llvm { + +// LanaiMachineFunctionInfo - This class is derived from MachineFunction and +// contains private Lanai target-specific information for each MachineFunction. +class LanaiMachineFunctionInfo : public MachineFunctionInfo { + virtual void anchor(); + + MachineFunction &MF; + + // SRetReturnReg - Lanai ABI require that sret lowering includes + // returning the value of the returned struct in a register. This field + // holds the virtual register into which the sret argument is passed. + unsigned SRetReturnReg; + + // GlobalBaseReg - keeps track of the virtual register initialized for + // use as the global base register. This is used for PIC in some PIC + // relocation models. + unsigned GlobalBaseReg; + + // VarArgsFrameIndex - FrameIndex for start of varargs area. + int VarArgsFrameIndex; + +public: + explicit LanaiMachineFunctionInfo(MachineFunction &MF) + : MF(MF), SRetReturnReg(0), GlobalBaseReg(0), VarArgsFrameIndex(0) {} + + unsigned getSRetReturnReg() const { return SRetReturnReg; } + void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; } + + unsigned getGlobalBaseReg(); + + int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } + void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_LANAIMACHINEFUNCTIONINFO_H Index: lib/Target/Lanai/LanaiMachineFunctionInfo.cpp =================================================================== --- lib/Target/Lanai/LanaiMachineFunctionInfo.cpp +++ lib/Target/Lanai/LanaiMachineFunctionInfo.cpp @@ -0,0 +1,23 @@ +//===-- LanaiMachineFuctionInfo.cpp - Lanai machine function info ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LanaiMachineFunctionInfo.h" + +using namespace llvm; + +void LanaiMachineFunctionInfo::anchor() {} + +unsigned LanaiMachineFunctionInfo::getGlobalBaseReg() { + // Return if it has already been initialized. + if (GlobalBaseReg) + return GlobalBaseReg; + + return GlobalBaseReg = + MF.getRegInfo().createVirtualRegister(&Lanai::GPRRegClass); +} Index: lib/Target/Lanai/LanaiMemAluCombiner.cpp =================================================================== --- lib/Target/Lanai/LanaiMemAluCombiner.cpp +++ lib/Target/Lanai/LanaiMemAluCombiner.cpp @@ -0,0 +1,421 @@ +//===-- LanaiMemAluCombiner.cpp - Pass to combine memory & ALU operations -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Simple pass to combine memory and ALU operations +// +// The Lanai ISA supports instructions where a load/store modifies the base +// register used in the load/store operation. This pass finds suitable +// load/store and ALU instructions and combines them into one instruction. +// +// For example, +// ld [ %r6 -- ], %r12 +// is a supported instruction that is not currently generated by the instruction +// selection pass of this backend. This pass generates these instructions by +// merging +// add %r6, -4, %r6 +// followed by +// ld [ %r6 ], %r12 +// in the same machine basic block into one machine instruction. +//===----------------------------------------------------------------------===// + +#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/CodeGen/RegisterScavenging.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetInstrInfo.h" +using namespace llvm; + +#define GET_INSTRMAP_INFO +#include "LanaiGenInstrInfo.inc" + +#define DEBUG_TYPE "lanai-mem-alu-combiner" + +STATISTIC(NumLdStAluCombined, "Number of memory and ALU instructions combined"); + +static llvm::cl::opt DisableMemAluCombiner( + "disable-lanai-mem-alu-combiner", llvm::cl::init(false), + llvm::cl::desc("Do not combine ALU and memory operators"), + llvm::cl::Hidden); + +namespace llvm { +void initializeLanaiMemAluCombinerPass(PassRegistry &); +} // namespace llvm + +namespace { +typedef MachineBasicBlock::iterator MbbIterator; +typedef MachineFunction::iterator MfIterator; + +class LanaiMemAluCombiner : public MachineFunctionPass { +public: + static char ID; + explicit LanaiMemAluCombiner() : MachineFunctionPass(ID) { + initializeLanaiMemAluCombinerPass(*PassRegistry::getPassRegistry()); + } + + const char *getPassName() const override { + return "Lanai load / store optimization pass"; + } + + bool runOnMachineFunction(MachineFunction &F) override; + +private: + MbbIterator findClosestSuitableAluInstr(MachineBasicBlock *BB, + const MbbIterator &MemInstr, + bool Decrement); + void insertMergedInstruction(MachineBasicBlock *BB, + const MbbIterator &MemInstr, + const MbbIterator &AluInstr, bool Before); + bool combineMemAluInBasicBlock(MachineBasicBlock *BB); + + // Target machine description which we query for register names, data + // layout, etc. + const TargetInstrInfo *II; +}; +} // namespace + +char LanaiMemAluCombiner::ID = 0; + +INITIALIZE_PASS(LanaiMemAluCombiner, DEBUG_TYPE, + "Lanai memory ALU combiner pass", false, false); + +namespace { +bool isSpls(uint16_t Opcode) { return Lanai::splsIdempotent(Opcode) == Opcode; } + +// Determine the opcode for the merged instruction created by considering the +// old memory operation's opcode and whether the merged opcode will have an +// immediate offset. +unsigned mergedOpcode(unsigned OldOpcode, bool ImmediateOffset) { + switch (OldOpcode) { + case Lanai::LDW_RI: + case Lanai::LDW_RR: + if (ImmediateOffset) + return Lanai::LDW_RI; + return Lanai::LDW_RR; + case Lanai::LDHs_RI: + case Lanai::LDHs_RR: + if (ImmediateOffset) + return Lanai::LDHs_RI; + return Lanai::LDHs_RR; + case Lanai::LDHz_RI: + case Lanai::LDHz_RR: + if (ImmediateOffset) + return Lanai::LDHz_RI; + return Lanai::LDHz_RR; + case Lanai::LDBs_RI: + case Lanai::LDBs_RR: + if (ImmediateOffset) + return Lanai::LDBs_RI; + return Lanai::LDBs_RR; + case Lanai::LDBz_RI: + case Lanai::LDBz_RR: + if (ImmediateOffset) + return Lanai::LDBz_RI; + return Lanai::LDBz_RR; + case Lanai::SW_RI: + case Lanai::SW_RR: + if (ImmediateOffset) + return Lanai::SW_RI; + return Lanai::SW_RR; + case Lanai::STB_RI: + case Lanai::STB_RR: + if (ImmediateOffset) + return Lanai::STB_RI; + return Lanai::STB_RR; + case Lanai::STH_RI: + case Lanai::STH_RR: + if (ImmediateOffset) + return Lanai::STH_RI; + return Lanai::STH_RR; + default: + return 0; + } +} + +// Check if the machine instruction has non-volatile memory operands of the type +// supported for combining with ALU instructions. +bool isNonVolatileMemoryOp(const MachineInstr &MI) { + if (!MI.hasOneMemOperand()) + return false; + + // Determine if the machine instruction is a supported memory operation by + // testing if the computed merge opcode is a valid memory operation opcode. + if (mergedOpcode(MI.getOpcode(), false) == 0) + return false; + + const MachineMemOperand *MemOperand = *MI.memoperands_begin(); + + // Don't move volatile memory accesses + if (MemOperand->isVolatile()) + return false; + + return true; +} + +// Test to see if two machine operands are of the same type. This test is less +// strict than the MachineOperand::isIdenticalTo function. +bool isSameOperand(const MachineOperand &Op1, const MachineOperand &Op2) { + if (Op1.getType() != Op2.getType()) + return false; + + switch (Op1.getType()) { + case MachineOperand::MO_Register: + return Op1.getReg() == Op2.getReg(); + case MachineOperand::MO_Immediate: + return Op1.getImm() == Op2.getImm(); + default: + return false; + } +} + +bool isZeroOperand(const MachineOperand &Op) { + return ((Op.isReg() && Op.getReg() == Lanai::R0) || + (Op.isImm() && Op.getImm() == 0)); +} + +// Determines whether a register is used by an instruction. +bool InstrUsesReg(const MbbIterator &Instr, const MachineOperand *Reg) { + for (MachineInstr::const_mop_iterator Mop = Instr->operands_begin(); + Mop != Instr->operands_end(); ++Mop) { + if (isSameOperand(*Mop, *Reg)) + return true; + } + return false; +} + +// Converts between machine opcode and AluCode. +// Flag using/modifying ALU operations should not be considered for merging and +// are omitted from this list. +LPAC::AluCode mergedAluCode(unsigned AluOpcode) { + switch (AluOpcode) { + case Lanai::ADD_I_LO: + case Lanai::ADD_R: + return LPAC::ADD; + case Lanai::SUB_I_LO: + case Lanai::SUB_R: + return LPAC::SUB; + case Lanai::AND_I_LO: + case Lanai::AND_R: + return LPAC::AND; + case Lanai::OR_I_LO: + case Lanai::OR_R: + return LPAC::OR; + case Lanai::XOR_I_LO: + case Lanai::XOR_R: + return LPAC::XOR; + case Lanai::SHL_I: + case Lanai::SHL_R: + return LPAC::SHL; + case Lanai::SRL_I: + case Lanai::SRL_R: + return LPAC::SRL; + case Lanai::SRA_I: + case Lanai::SRA_R: + return LPAC::SRA; + default: + return LPAC::UNKNOWN; + } +} + +// Insert a new combined memory and ALU operation instruction. +// +// This function builds a new machine instruction using the MachineInstrBuilder +// class and inserts it before the memory instruction. +void LanaiMemAluCombiner::insertMergedInstruction(MachineBasicBlock *BB, + const MbbIterator &MemInstr, + const MbbIterator &AluInstr, + bool Before) { + // Insert new combined load/store + alu operation + MachineOperand Dest = MemInstr->getOperand(0); + MachineOperand Base = MemInstr->getOperand(1); + MachineOperand MemOffset = MemInstr->getOperand(2); + MachineOperand AluOffset = AluInstr->getOperand(2); + + // Abort if ALU offset is not a register or immediate + assert((AluOffset.isReg() || AluOffset.isImm()) && + "Unsupported operand type in merge"); + + // Determined merged instructions opcode and ALU code + LPAC::AluCode AluOpcode = mergedAluCode(AluInstr->getOpcode()); + unsigned NewOpc = mergedOpcode(MemInstr->getOpcode(), AluOffset.isImm()); + + assert(AluOpcode != LPAC::UNKNOWN && "Unknown ALU code in merging"); + assert(NewOpc != 0 && "Unknown merged node opcode"); + + // Build and insert new machine instruction + MachineInstrBuilder InstrBuilder = + BuildMI(*BB, MemInstr, MemInstr->getDebugLoc(), II->get(NewOpc)); + InstrBuilder.addReg(Dest.getReg(), getDefRegState(true)); + InstrBuilder.addReg(Base.getReg(), getKillRegState(true)); + + // Add offset to machine instruction + if (AluOffset.isReg()) { + InstrBuilder.addReg(AluOffset.getReg()); + } else if (AluOffset.isImm()) { + InstrBuilder.addImm(AluOffset.getImm()); + } else { + llvm_unreachable("Unsupported ld/st ALU merge."); + } + + // Create a pre-op if the ALU operation preceded the memory operation or the + // MemOffset is non-zero (i.e. the memory value should be adjusted before + // accessing it), else create a post-op. + if (Before || !isZeroOperand(MemOffset)) { + InstrBuilder.addImm(LPAC::makePreOp(AluOpcode)); + } else { + InstrBuilder.addImm(LPAC::makePostOp(AluOpcode)); + } + + // Transfer memory operands. + InstrBuilder->setMemRefs(MemInstr->memoperands_begin(), + MemInstr->memoperands_end()); +} + +// Function determines if ALU operation (in alu_iter) can be combined with +// a load/store with base and offset. +bool isSuitableAluInstr(bool IsSpls, const MbbIterator &AluIter, + const MachineOperand &Base, + const MachineOperand &offset) { + // ALU operations have 3 operands + if (AluIter->getNumOperands() != 3) + return false; + + MachineOperand *Dest = &AluIter->getOperand(0); + MachineOperand *Op1 = &AluIter->getOperand(1); + MachineOperand *Op2 = &AluIter->getOperand(2); + + // Only match instructions using the base register as destination and with the + // base and first operand equal + if (!isSameOperand(*Dest, Base) || !isSameOperand(*Dest, *Op1)) + return false; + + if (Op2->isImm()) { + // It is not a match if the 2nd operand in the ALU operation is an + // immediate but the ALU operation is not an addition. + if (AluIter->getOpcode() != Lanai::ADD_I_LO) + return false; + + if (offset.isReg() && offset.getReg() == Lanai::R0) + return true; + + if (offset.isImm() && + ((offset.getImm() == 0 && + // Check that the Op2 would fit in the immediate field of the + // memory operation. + ((IsSpls && isInt<10>(Op2->getImm())) || + (!IsSpls && isInt<16>(Op2->getImm())))) || + offset.getImm() == Op2->getImm())) { + return true; + } + } else if (Op2->isReg()) { + // The offset and 2nd operand are both registers and equal + if (offset.isReg() && Op2->getReg() == offset.getReg()) + return true; + } else { + // Only consider operations with register or immediate values + return false; + } + + return false; +} + +MbbIterator LanaiMemAluCombiner::findClosestSuitableAluInstr( + MachineBasicBlock *BB, const MbbIterator &MemInstr, const bool Decrement) { + MachineOperand *Base = &MemInstr->getOperand(1); + MachineOperand *Offset = &MemInstr->getOperand(2); + bool IsSpls = isSpls(MemInstr->getOpcode()); + + MbbIterator First = MemInstr; + MbbIterator Last = Decrement ? BB->begin() : BB->end(); + + while (First != Last) { + Decrement ? --First : ++First; + + // Skip over debug instructions + if (First->isDebugValue()) + continue; + + if (isSuitableAluInstr(IsSpls, First, *Base, *Offset)) { + return First; + } + + // Usage of the base register of a form not suitable for merging + if (First != Last && InstrUsesReg(First, Base)) { + break; + } + } + + return MemInstr; +} + +bool LanaiMemAluCombiner::combineMemAluInBasicBlock(MachineBasicBlock *BB) { + bool Modified = false; + + MbbIterator MBBIter = BB->begin(), End = BB->end(); + while (MBBIter != End) { + bool IsMemOp = isNonVolatileMemoryOp(*MBBIter); + + if (IsMemOp) { + MachineOperand AluOperand = MBBIter->getOperand(3); + unsigned int DestReg = MBBIter->getOperand(0).getReg(), + BaseReg = MBBIter->getOperand(1).getReg(); + assert(AluOperand.isImm() && "Unexpected memory operator type"); + LPAC::AluCode AluOpcode = static_cast(AluOperand.getImm()); + + // Skip memory operations that already modify the base register or if + // the destination and base register are the same + if (!LPAC::modifiesOp(AluOpcode) && DestReg != BaseReg) { + for (int Inc = 0; Inc <= 1; ++Inc) { + MbbIterator AluIter = + findClosestSuitableAluInstr(BB, MBBIter, Inc == 0); + if (AluIter != MBBIter) { + insertMergedInstruction(BB, MBBIter, AluIter, Inc == 0); + + ++NumLdStAluCombined; + Modified = true; + + // Erase the matching ALU instruction + BB->erase(AluIter); + // Erase old load/store instruction + BB->erase(MBBIter++); + break; + } + } + } + } + if (MBBIter == End) + break; + ++MBBIter; + } + + return Modified; +} + +// Driver function that iterates over the machine basic building blocks of a +// machine function +bool LanaiMemAluCombiner::runOnMachineFunction(MachineFunction &MF) { + bool Modified = false; + II = MF.getSubtarget().getInstrInfo(); + + if (DisableMemAluCombiner) + return false; + + MfIterator End = MF.end(); + for (MfIterator MFI = MF.begin(); MFI != End; ++MFI) { + Modified |= combineMemAluInBasicBlock(&*MFI); + } + return Modified; +} +} // namespace + +FunctionPass *llvm::createLanaiMemAluCombinerPass() { + return new LanaiMemAluCombiner(); +} Index: lib/Target/Lanai/LanaiRegisterInfo.h =================================================================== --- lib/Target/Lanai/LanaiRegisterInfo.h +++ lib/Target/Lanai/LanaiRegisterInfo.h @@ -0,0 +1,65 @@ +//===- LanaiRegisterInfo.h - Lanai Register Information Impl ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Lanai implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_LANAIREGISTERINFO_H +#define LLVM_LIB_TARGET_LANAI_LANAIREGISTERINFO_H + +#include "llvm/Target/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "LanaiGenRegisterInfo.inc" + +namespace llvm { + +class TargetInstrInfo; +class Type; + +struct LanaiRegisterInfo : public LanaiGenRegisterInfo { + const TargetInstrInfo &TII; + + explicit LanaiRegisterInfo(const TargetInstrInfo &TII); + + const uint32_t *getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID) const override; + + // Code Generation virtual methods. + const uint16_t * + getCalleeSavedRegs(const MachineFunction *MF = 0) const override; + + BitVector getReservedRegs(const MachineFunction &MF) const override; + + bool requiresRegisterScavenging(const MachineFunction &MF) const override; + + bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const override; + + void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + unsigned FIOperandNum, + RegScavenger *RS = NULL) const override; + + bool canRealignStack(const MachineFunction &MF) const override; + + // Debug information queries. + unsigned getRARegister() const; + unsigned getFrameRegister(const MachineFunction &MF) const override; + unsigned getBaseRegister() const; + bool hasBasePointer(const MachineFunction &MF) const; + + // Exception handling queries. + unsigned getEHExceptionRegister() const; + unsigned getEHHandlerRegister() const; + int getDwarfRegNum(unsigned RegNum, bool IsEH) const; +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_LANAIREGISTERINFO_H Index: lib/Target/Lanai/LanaiRegisterInfo.cpp =================================================================== --- lib/Target/Lanai/LanaiRegisterInfo.cpp +++ lib/Target/Lanai/LanaiRegisterInfo.cpp @@ -0,0 +1,284 @@ +//===-- LanaiRegisterInfo.cpp - Lanai Register Information ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Lanai implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "Lanai.h" +#include "LanaiRegisterInfo.h" +#include "LanaiSubtarget.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetInstrInfo.h" + +#define GET_REGINFO_TARGET_DESC +#include "LanaiGenRegisterInfo.inc" + +using namespace llvm; + +LanaiRegisterInfo::LanaiRegisterInfo(const TargetInstrInfo &TII) + : LanaiGenRegisterInfo(Lanai::RCA), TII(TII) {} + +const uint16_t * +LanaiRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + return CSR_SaveList; +} + +BitVector LanaiRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + + Reserved.set(Lanai::R0); + Reserved.set(Lanai::R1); + Reserved.set(Lanai::PC); + Reserved.set(Lanai::R2); + Reserved.set(Lanai::SP); + Reserved.set(Lanai::R4); + Reserved.set(Lanai::FP); + Reserved.set(Lanai::R5); + Reserved.set(Lanai::RR1); + Reserved.set(Lanai::R10); + Reserved.set(Lanai::RR2); + Reserved.set(Lanai::R11); + Reserved.set(Lanai::RCA); + Reserved.set(Lanai::R15); + if (hasBasePointer(MF)) + Reserved.set(getBaseRegister()); + return Reserved; +} + +bool LanaiRegisterInfo::requiresRegisterScavenging( + const MachineFunction &MF) const { + return true; +} + +bool LanaiRegisterInfo::trackLivenessAfterRegAlloc( + const MachineFunction &MF) const { + return true; +} + +static bool isALUArithLoOpcode(unsigned Opcode) { + switch (Opcode) { + case Lanai::ADD_I_LO: + case Lanai::SUB_I_LO: + case Lanai::ADD_F_I_LO: + case Lanai::SUB_F_I_LO: + case Lanai::ADDC_I_LO: + case Lanai::SUBB_I_LO: + case Lanai::ADDC_F_I_LO: + case Lanai::SUBB_F_I_LO: + return true; + default: + return false; + } +} + +static unsigned getOppositeALULoOpcode(unsigned Opcode) { + switch (Opcode) { + case Lanai::ADD_I_LO: + return Lanai::SUB_I_LO; + case Lanai::SUB_I_LO: + return Lanai::ADD_I_LO; + case Lanai::ADD_F_I_LO: + return Lanai::SUB_F_I_LO; + case Lanai::SUB_F_I_LO: + return Lanai::ADD_F_I_LO; + case Lanai::ADDC_I_LO: + return Lanai::SUBB_I_LO; + case Lanai::SUBB_I_LO: + return Lanai::ADDC_I_LO; + case Lanai::ADDC_F_I_LO: + return Lanai::SUBB_F_I_LO; + case Lanai::SUBB_F_I_LO: + return Lanai::ADDC_F_I_LO; + default: + llvm_unreachable("Invalid ALU lo opcode"); + } +} + +static unsigned getRRMOpcodeVariant(unsigned Opcode) { + switch (Opcode) { + case Lanai::LDBs_RI: + return Lanai::LDBs_RR; + case Lanai::LDBz_RI: + return Lanai::LDBz_RR; + case Lanai::LDHs_RI: + return Lanai::LDHs_RR; + case Lanai::LDHz_RI: + return Lanai::LDHz_RR; + case Lanai::LDW_RI: + return Lanai::LDW_RR; + case Lanai::STB_RI: + return Lanai::STB_RR; + case Lanai::STH_RI: + return Lanai::STH_RR; + case Lanai::SW_RI: + return Lanai::SW_RR; + default: + llvm_unreachable("Opcode has no RRM variant"); + } +} + +void LanaiRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const { + assert(SPAdj == 0 && "Unexpected"); + + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering(); + bool HasFP = TFI->hasFP(MF); + DebugLoc DL = MI.getDebugLoc(); + + int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); + + int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) + + MI.getOperand(FIOperandNum + 1).getImm(); + + // Addressable stack objects are addressed using neg. offsets from fp + // or pos. offsets from sp/basepointer + if (!HasFP || (needsStackRealignment(MF) && FrameIndex >= 0)) + Offset += MF.getFrameInfo()->getStackSize(); + + unsigned FrameReg = getFrameRegister(MF); + if (FrameIndex >= 0) { + if (hasBasePointer(MF)) + FrameReg = getBaseRegister(); + else if (needsStackRealignment(MF)) + FrameReg = Lanai::SP; + } + + // Replace frame index with a frame pointer reference. + // If the offset is small enough to fit in the immediate field, directly + // encode it. + // Otherwise scavenge a register and encode it into a MOVHI, OR_I_LO sequence. + if ((isSPLSOpcode(MI.getOpcode()) && !isInt<10>(Offset)) || + !isInt<16>(Offset)) { + assert(RS && "Register scavenging must be on"); + unsigned Reg = RS->FindUnusedReg(&Lanai::GPRRegClass); + if (!Reg) + Reg = RS->scavengeRegister(&Lanai::GPRRegClass, II, SPAdj); + assert(Reg && "Register scavenger failed"); + + bool HasNegOffset = false; + // ALU ops have unsigned immediate values. If the Offset is negative, we + // negate it here and reverse the opcode later. + if (Offset < 0) { + HasNegOffset = true; + Offset = -Offset; + } + + if (!isInt<16>(Offset)) { + // Reg = hi(offset) | lo(offset) + BuildMI(*MI.getParent(), II, DL, TII.get(Lanai::MOVHI), Reg) + .addImm(static_cast(Offset) >> 16); + BuildMI(*MI.getParent(), II, DL, TII.get(Lanai::OR_I_LO), Reg) + .addReg(Reg) + .addImm(Offset & 0xffffU); + } else { + // Reg = mov(offset) + BuildMI(*MI.getParent(), II, DL, TII.get(Lanai::ADD_I_LO), Reg) + .addImm(0) + .addImm(Offset); + } + // Reg = FrameReg OP Reg + if (MI.getOpcode() == Lanai::ADD_I_LO) { + if (HasNegOffset) { + MI.setDesc(TII.get(Lanai::SUB_R)); + } else { + MI.setDesc(TII.get(Lanai::ADD_R)); + } + } else if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) { + MI.setDesc(TII.get(getRRMOpcodeVariant(MI.getOpcode()))); + if (HasNegOffset) { + // Change the ALU op (operand 3) from LPAC::ADD (the default) to + // LPAC::SUB with the already negated offset. + assert((MI.getOperand(3).getImm() == LPAC::ADD) && + "Unexpected ALU op in RRM instruction"); + MI.getOperand(3).setImm(LPAC::SUB); + } + } else { + MI.dump(); + llvm_unreachable("Unexpected opcode in frame index operation"); + } + + MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/false); + MI.getOperand(FIOperandNum + 1) + .ChangeToRegister(Reg, /*isDef=*/false, /*isImp=*/false, + /*isKill=*/true); + return; + } + + // ALU arithmetic ops take unsigned immediates. If the offset is negative, + // we replace the instruction with one that inverts the opcode and negates + // the immediate. + if ((Offset < 0) && isALUArithLoOpcode(MI.getOpcode())) { + unsigned NewOpcode = getOppositeALULoOpcode(MI.getOpcode()); + // We know this is an ALU op, so we know the operands are as follows: + // 0: destination register + // 1: source register (frame register) + // 2: immediate + BuildMI(*MI.getParent(), II, DL, TII.get(NewOpcode), + MI.getOperand(0).getReg()) + .addReg(FrameReg) + .addImm(-Offset); + MI.eraseFromParent(); + } else { + MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/false); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); + } +} + +bool LanaiRegisterInfo::hasBasePointer(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + // When we need stack realignment and there are dynamic allocas, we can't + // reference off of the stack pointer, so we reserve a base pointer. + if (needsStackRealignment(MF) && MFI->hasVarSizedObjects()) + return true; + + return false; +} + +unsigned LanaiRegisterInfo::getRARegister() const { return Lanai::RCA; } + +unsigned LanaiRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + return Lanai::FP; +} + +unsigned LanaiRegisterInfo::getBaseRegister() const { return Lanai::R14; } + +bool LanaiRegisterInfo::canRealignStack(const MachineFunction &MF) const { + if (!TargetRegisterInfo::canRealignStack(MF)) + return false; + return true; +} + +unsigned LanaiRegisterInfo::getEHExceptionRegister() const { + llvm_unreachable("no exception support"); + return 0; +} + +unsigned LanaiRegisterInfo::getEHHandlerRegister() const { + llvm_unreachable("no exception support"); + return 0; +} + +const uint32_t * +LanaiRegisterInfo::getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID CC) const { + return CSR_RegMask; +} Index: lib/Target/Lanai/LanaiRegisterInfo.td =================================================================== --- lib/Target/Lanai/LanaiRegisterInfo.td +++ lib/Target/Lanai/LanaiRegisterInfo.td @@ -0,0 +1,64 @@ +//===- LanaiRegisterInfo.td - Lanai Register defs ------------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Declarations that describe the Lanai register file +//===----------------------------------------------------------------------===// + +// Registers are identified with 5-bit ID numbers. +class LanaiReg num, string n, list subregs = [], + list altNames = []> : Register { + field bits<5> Num; + let Num = num; + let Namespace = "Lanai"; + let SubRegs = subregs; +} + +let Namespace = "Lanai" in { + def sub_32 : SubRegIndex<32>; +} + +// Integer registers +foreach i = 0-31 in { + def R#i : LanaiReg, DwarfRegNum<[i]>; +} + +// Register aliases +let SubRegIndices = [sub_32] in { + def PC : LanaiReg< 2, "pc", [R2]>, DwarfRegAlias; + def SP : LanaiReg< 4, "sp", [R4]>, DwarfRegAlias; + def FP : LanaiReg< 5, "fp", [R5]>, DwarfRegAlias; + def RV : LanaiReg< 8, "rv", [R8]>, DwarfRegAlias; + def RR1 : LanaiReg<10, "rr1", [R10]>, DwarfRegAlias; + def RR2 : LanaiReg<11, "rr2", [R11]>, DwarfRegAlias; + def RCA : LanaiReg<15, "rca", [R15]>, DwarfRegAlias; +} + +// Define a status register to capture the dependencies between the set flag +// and setcc instructions +def SR : LanaiReg< 0, "sw">; + +// Register classes. +def GPR : RegisterClass<"Lanai", [i32], 32, + (add R3, R9, R12, R13, R14, R16, R17, + (sequence "R%i", 20, 31), + R6, R7, R18, R19, // registers for passing arguments + R15, RCA, // register for constant addresses + R10, RR1, R11, RR2, // programmer controlled registers + R8, RV, // return value + R5, FP, // frame pointer + R4, SP, // stack pointer + R2, PC, // program counter + R1, // all 1s (0xffffffff) + R0 // constant 0 + )>; + +// Condition code register class +def CCR : RegisterClass<"Lanai", [i32], 32, (add SR)> { + let CopyCost = -1; // Don't allow copying of status registers + let isAllocatable = 0; +} Index: lib/Target/Lanai/LanaiSchedule.td =================================================================== --- lib/Target/Lanai/LanaiSchedule.td +++ lib/Target/Lanai/LanaiSchedule.td @@ -0,0 +1,66 @@ +//=-LanaiSchedule.td - Lanai Scheduling Definitions --*- tablegen -*-=========// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +def ALU_FU : FuncUnit; +def LDST_FU : FuncUnit; + +def IIC_ALU : InstrItinClass; +def IIC_LD : InstrItinClass; +def IIC_ST : InstrItinClass; + +def LanaiItinerary : ProcessorItineraries<[ALU_FU, LDST_FU],[],[ + InstrItinData]>, + InstrItinData]>, + InstrItinData]> +]>; + +def LanaiSchedModel : SchedMachineModel { + // Cycles for loads to access the cache [default = -1] + let LoadLatency = 2; + + // Max micro-ops that can be buffered for optimized loop dispatch/execution. + // [default = -1] + let LoopMicroOpBufferSize = 0; + + // Allow scheduler to assign default model to any unrecognized opcodes. + // [default = 1] + let CompleteModel = 0; + + // Max micro-ops that may be scheduled per cycle. [default = 1] + let IssueWidth = 1; + + // Determines which instructions are allowed in a group. 1 is an inorder + // CPU with variable latencies. [default = -1] + let MinLatency = 1; + + // Extra cycles for a mispredicted branch. [default = -1] + let MispredictPenalty = 10; + + // Enable Post RegAlloc Scheduler pass. [default = 0] + let PostRAScheduler = 0; + + // Max micro-ops that can be buffered. [default = -1] + let MicroOpBufferSize = 0; + + // Per-cycle resources tables. [default = NoItineraries] + let Itineraries = LanaiItinerary; +} + +def ALU : ProcResource<1> { let BufferSize = 0; } +def LdSt : ProcResource<1> { let BufferSize = 0; } + +def WriteLD : SchedWrite; +def WriteST : SchedWrite; +def WriteALU : SchedWrite; + +let SchedModel = LanaiSchedModel in { + def : WriteRes { let Latency = 2; } + def : WriteRes { let Latency = 2; } + def : WriteRes { let Latency = 1; } +} Index: lib/Target/Lanai/LanaiSelectionDAGInfo.h =================================================================== --- lib/Target/Lanai/LanaiSelectionDAGInfo.h +++ lib/Target/Lanai/LanaiSelectionDAGInfo.h @@ -0,0 +1,36 @@ +//===-- LanaiSelectionDAGInfo.h - Lanai SelectionDAG Info -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Lanai subclass for TargetSelectionDAGInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_LANAISELECTIONDAGINFO_H +#define LLVM_LIB_TARGET_LANAI_LANAISELECTIONDAGINFO_H + +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +class LanaiSelectionDAGInfo : public SelectionDAGTargetInfo { +public: + LanaiSelectionDAGInfo() = default; + + SDValue EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl, SDValue Chain, + SDValue Dst, SDValue Src, SDValue Size, + unsigned Align, bool isVolatile, + bool AlwaysInline, + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) const override; +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_LANAISELECTIONDAGINFO_H Index: lib/Target/Lanai/LanaiSelectionDAGInfo.cpp =================================================================== --- lib/Target/Lanai/LanaiSelectionDAGInfo.cpp +++ lib/Target/Lanai/LanaiSelectionDAGInfo.cpp @@ -0,0 +1,35 @@ +//===-- LanaiSelectionDAGInfo.cpp - Lanai SelectionDAG Info -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the LanaiSelectionDAGInfo class. +// +//===----------------------------------------------------------------------===// + +#include "LanaiSelectionDAGInfo.h" + +#include "LanaiTargetMachine.h" + +#define DEBUG_TYPE "lanai-selectiondag-info" + +namespace llvm { + +SDValue LanaiSelectionDAGInfo::EmitTargetCodeForMemcpy( + SelectionDAG &DAG, SDLoc dl, SDValue Chain, SDValue Dst, SDValue Src, + SDValue Size, unsigned Align, bool isVolatile, bool AlwaysInline, + MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const { + // This requires the copy size to be a constant, preferably + // within a subtarget-specific limit. + ConstantSDNode *ConstantSize = dyn_cast(Size); + if (!ConstantSize) + return SDValue(); + + return SDValue(); +} + +} // namespace llvm Index: lib/Target/Lanai/LanaiSetflagAluCombiner.cpp =================================================================== --- lib/Target/Lanai/LanaiSetflagAluCombiner.cpp +++ lib/Target/Lanai/LanaiSetflagAluCombiner.cpp @@ -0,0 +1,344 @@ +//===-- LanaiSetflagAluCombiner.cpp - Pass to combine set flag & ALU ops --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/CodeGen/RegisterScavenging.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetInstrInfo.h" +using namespace llvm; + +#define DEBUG_TYPE "lanai-setflag-alu-combiner" + +STATISTIC(NumSetflagAluCombined, + "Number of SET_FLAG and ALU instructions combined"); + +static llvm::cl::opt DisableSetflagAluCombiner( + "disable-lanai-setflag-alu-combiner", llvm::cl::init(false), + llvm::cl::desc("Do not combine SET_FLAG and ALU operators"), + llvm::cl::Hidden); + +namespace llvm { +void initializeLanaiSetflagAluCombinerPass(PassRegistry &); +} // namespace llvm + +namespace { +typedef MachineBasicBlock::iterator MbbIterator; +typedef MachineFunction::iterator MfIterator; + +class LanaiSetflagAluCombiner : public MachineFunctionPass { +public: + static char ID; + LanaiSetflagAluCombiner() : MachineFunctionPass(ID) { + initializeLanaiSetflagAluCombinerPass(*PassRegistry::getPassRegistry()); + } + + const char *getPassName() const override { + return "Lanai SET_FLAG ALU combiner pass"; + } + + bool runOnMachineFunction(MachineFunction &F) override; + +private: + bool CombineSetflagAluInBasicBlock(MachineFunction *MF, + MachineBasicBlock *BB); + + // Target machine description which we query for register names, data + // layout, etc. + const TargetInstrInfo *TII; +}; +} // namespace + +char LanaiSetflagAluCombiner::ID = 0; + +INITIALIZE_PASS(LanaiSetflagAluCombiner, DEBUG_TYPE, + "Lanai SET_FLAG ALU combiner pass", false, false); + + +namespace { + +const unsigned kInvalid = -1; + +static unsigned flagSettingOpcodeVariant(unsigned OldOpcode) { + switch (OldOpcode) { + case Lanai::ADD_I_HI: + return Lanai::ADD_F_I_HI; + case Lanai::ADD_I_LO: + return Lanai::ADD_F_I_LO; + case Lanai::ADD_R: + return Lanai::ADD_F_R; + case Lanai::ADD_R_CC: + return Lanai::ADD_F_R_CC; + case Lanai::ADDC_I_HI: + return Lanai::ADDC_F_I_HI; + case Lanai::ADDC_I_LO: + return Lanai::ADDC_F_I_LO; + case Lanai::ADDC_R: + return Lanai::ADDC_F_R; + case Lanai::ADDC_R_CC: + return Lanai::ADDC_F_R_CC; + case Lanai::AND_I_HI: + return Lanai::AND_F_I_HI; + case Lanai::AND_I_LO: + return Lanai::AND_F_I_LO; + case Lanai::AND_R: + return Lanai::AND_F_R; + case Lanai::AND_R_CC: + return Lanai::AND_F_R_CC; + case Lanai::OR_I_HI: + return Lanai::OR_F_I_HI; + case Lanai::OR_I_LO: + return Lanai::OR_F_I_LO; + case Lanai::OR_R: + return Lanai::OR_F_R; + case Lanai::OR_R_CC: + return Lanai::OR_F_R_CC; + case Lanai::SHL_I: + return Lanai::SHL_F_I; + case Lanai::SHL_R: + return Lanai::SHL_F_R; + case Lanai::SRL_I: + return Lanai::SRL_F_I; + case Lanai::SRL_R: + return Lanai::SRL_F_R; + case Lanai::SHA_I: + return Lanai::SHA_F_I; + case Lanai::SRA_I: + return Lanai::SRA_F_I; + case Lanai::SRA_R: + return Lanai::SRA_F_R; + case Lanai::SUB_I_HI: + return Lanai::SUB_F_I_HI; + case Lanai::SUB_I_LO: + return Lanai::SUB_F_I_LO; + case Lanai::SUB_R: + return Lanai::SUB_F_R; + case Lanai::SUB_R_CC: + return Lanai::SUB_F_R_CC; + case Lanai::SUBB_I_HI: + return Lanai::SUBB_F_I_HI; + case Lanai::SUBB_I_LO: + return Lanai::SUBB_F_I_LO; + case Lanai::SUBB_R: + return Lanai::SUBB_F_R; + case Lanai::SUBB_R_CC: + return Lanai::SUBB_F_R_CC; + case Lanai::XOR_I_HI: + return Lanai::XOR_F_I_HI; + case Lanai::XOR_I_LO: + return Lanai::XOR_F_I_LO; + case Lanai::XOR_R: + return Lanai::XOR_F_R; + case Lanai::XOR_R_CC: + return Lanai::XOR_F_R_CC; + default: + return kInvalid; + } +} + +// Returns whether opcode corresponds to instruction that sets flags. +static bool isFlagSettingInstruction(unsigned Opcode) { + switch (Opcode) { + case Lanai::ADDC_F_I_HI: + case Lanai::ADDC_F_I_LO: + case Lanai::ADDC_F_R: + case Lanai::ADDC_F_R_CC: + case Lanai::ADD_F_I_HI: + case Lanai::ADD_F_I_LO: + case Lanai::ADD_F_R: + case Lanai::ADD_F_R_CC: + case Lanai::AND_F_I_HI: + case Lanai::AND_F_I_LO: + case Lanai::AND_F_R: + case Lanai::AND_F_R_CC: + case Lanai::OR_F_I_HI: + case Lanai::OR_F_I_LO: + case Lanai::OR_F_R: + case Lanai::OR_F_R_CC: + case Lanai::SFSUB_F_RI: + case Lanai::SFSUB_F_RR: + case Lanai::SHA_F_I: + case Lanai::SHL_F_I: + case Lanai::SHL_F_R: + case Lanai::SRA_F_I: + case Lanai::SRA_F_R: + case Lanai::SRL_F_I: + case Lanai::SRL_F_R: + case Lanai::SUBB_F_I_HI: + case Lanai::SUBB_F_I_LO: + case Lanai::SUBB_F_R: + case Lanai::SUBB_F_R_CC: + case Lanai::SUB_F_I_HI: + case Lanai::SUB_F_I_LO: + case Lanai::SUB_F_R: + case Lanai::SUB_F_R_CC: + case Lanai::XOR_F_I_HI: + case Lanai::XOR_F_I_LO: + case Lanai::XOR_F_R: + case Lanai::XOR_F_R_CC: + return true; + default: + return false; + } +} + +// Return the Conditional Code operand for a given instruction kind. For +// example, operand at index 1 of a BRIND_CC instruction is the conditional code +// (eq, ne, etc.). Returns -1 if the instruction does not have a conditional +// code. +static int getCCOperandPosition(unsigned Opcode) { + switch (Opcode) { + case Lanai::BRIND_CC: + case Lanai::BRIND_CCA: + case Lanai::BRR: + case Lanai::BRCC: + case Lanai::SCC: + return 1; + case Lanai::SELECT: + case Lanai::ADDC_F_R_CC: + case Lanai::ADDC_R_CC: + case Lanai::ADD_F_R_CC: + case Lanai::ADD_R_CC: + case Lanai::AND_F_R_CC: + case Lanai::AND_R_CC: + case Lanai::OR_F_R_CC: + case Lanai::OR_R_CC: + case Lanai::SUBB_F_R_CC: + case Lanai::SUBB_R_CC: + case Lanai::SUB_F_R_CC: + case Lanai::SUB_R_CC: + case Lanai::XOR_F_R_CC: + case Lanai::XOR_R_CC: + return 3; + default: + return -1; + } +} + +// Returns true if instruction is a lowered SET_FLAG instruction with 0/R0 as +// the first operand and whose conditional code is such that it can be merged +// (i.e., EQ, NE, PL and MI). +static bool isSuitableSetflag(MbbIterator Instruction, MbbIterator End) { + unsigned Opcode = Instruction->getOpcode(); + if (Opcode == Lanai::SFSUB_F_RI || Opcode == Lanai::SFSUB_F_RR) { + const MachineOperand &Operand = Instruction->getOperand(1); + if (Operand.isReg() && Operand.getReg() != Lanai::R0) { + return false; + } + if (Operand.isImm() && Operand.getImm() != 0) { + return false; + } + + MbbIterator SCCUserIter = Instruction; + while (SCCUserIter != End) { + ++SCCUserIter; + // Early exit when encountering flag setting instruction. + if (isFlagSettingInstruction(SCCUserIter->getOpcode())) { + break; + } + int CCIndex = getCCOperandPosition(SCCUserIter->getOpcode()); + if (CCIndex != -1) { + LPCC::CondCode CC = static_cast( + SCCUserIter->getOperand(CCIndex).getImm()); + if (CC != LPCC::ICC_EQ && CC != LPCC::ICC_NE && CC != LPCC::ICC_PL && + CC != LPCC::ICC_MI) { + return false; + } + } + } + + return true; + } + + return false; +} + +// Combines a SET_FLAG instruction comparing a register with 0 and an ALU +// operation that sets the same register used in the comparison into a single +// flag setting ALU instruction (both instructions combined are removed and new +// flag setting ALU operation inserted where ALU instruction was). +bool LanaiSetflagAluCombiner::CombineSetflagAluInBasicBlock( + MachineFunction *MF, MachineBasicBlock *BB) { + bool Modified = false; + + MbbIterator SetflagIter = BB->begin(); + MbbIterator End = BB->end(); + MbbIterator Begin = BB->begin(); + while (SetflagIter != End) { + bool Replaced = false; + if (isSuitableSetflag(SetflagIter, End)) { + MbbIterator AluIter = SetflagIter; + while (AluIter != Begin) { + --AluIter; + // Skip debug instructions. Debug instructions don't affect codegen. + if (AluIter->isDebugValue()) { + continue; + } + // Early exit when encountering flag setting instruction. + if (isFlagSettingInstruction(AluIter->getOpcode())) { + break; + } + // Check that output of AluIter is equal to input of SetflagIter. + if (AluIter->getNumOperands() > 1 && AluIter->getOperand(0).isReg() && + (AluIter->getOperand(0).getReg() == + SetflagIter->getOperand(0).getReg())) { + unsigned NewOpc = flagSettingOpcodeVariant(AluIter->getOpcode()); + if (NewOpc == kInvalid) + break; + + // Change the ALU instruction to the flag setting variant. + AluIter->setDesc(TII->get(NewOpc)); + AluIter->addImplicitDefUseOperands(*MF); + + Replaced = true; + ++NumSetflagAluCombined; + break; + } + } + // Erase the setflag instruction if merged. + if (Replaced) { + BB->erase(SetflagIter++); + } + } + + Modified |= Replaced; + if (SetflagIter == End) + break; + if (!Replaced) + ++SetflagIter; + } + + return Modified; +} + +// Driver function that iterates over the machine basic building blocks of a +// machine function +bool LanaiSetflagAluCombiner::runOnMachineFunction(MachineFunction &MF) { + if (DisableSetflagAluCombiner) { + return false; + } + + TII = MF.getSubtarget().getInstrInfo(); + + bool Modified = false; + MfIterator End = MF.end(); + for (MfIterator MFI = MF.begin(); MFI != End; ++MFI) { + Modified |= CombineSetflagAluInBasicBlock(&MF, &*MFI); + } + return Modified; +} +} // namespace + +FunctionPass *llvm::createLanaiSetflagAluCombinerPass() { + return new LanaiSetflagAluCombiner(); +} Index: lib/Target/Lanai/LanaiSubtarget.h =================================================================== --- lib/Target/Lanai/LanaiSubtarget.h +++ lib/Target/Lanai/LanaiSubtarget.h @@ -0,0 +1,79 @@ +//=====-- LanaiSubtarget.h - Define Subtarget for the 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 declares the Lanai specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_LANAISUBTARGET_H +#define LLVM_LIB_TARGET_LANAI_LANAISUBTARGET_H + +#include + +#include "LanaiFrameLowering.h" +#include "LanaiISelLowering.h" +#include "LanaiInstrInfo.h" +#include "LanaiSelectionDAGInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +#define GET_SUBTARGETINFO_HEADER +#include "LanaiGenSubtargetInfo.inc" + +namespace llvm { + +class LanaiSubtarget : public LanaiGenSubtargetInfo { +public: + // This constructor initializes the data members to match that + // of the specified triple. + LanaiSubtarget(const Triple &TargetTriple, StringRef Cpu, + StringRef FeatureString, TargetMachine *TM, + const TargetOptions &Options, Reloc::Model RelocationModel, + CodeModel::Model CodeModel, CodeGenOpt::Level OptLevel); + + // ParseSubtargetFeatures - Parses features string setting specified + // subtarget options. Definition of function is auto generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + + LanaiSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); + + void initSubtargetFeatures(StringRef CPU, StringRef FS); + + bool enableMachineScheduler() const override { return true; } + + const LanaiInstrInfo *getInstrInfo() const override { return &instr_info_; } + + const TargetFrameLowering *getFrameLowering() const override { + return &frame_lowering_; + } + + const LanaiRegisterInfo *getRegisterInfo() const override { + return &instr_info_.getRegisterInfo(); + } + + const LanaiTargetLowering *getTargetLowering() const override { + return &target_lowering_info_; + } + + const LanaiSelectionDAGInfo *getSelectionDAGInfo() const override { + return &selection_dag_info_; + } + +private: + virtual void anchor(); + LanaiFrameLowering frame_lowering_; + LanaiInstrInfo instr_info_; + LanaiTargetLowering target_lowering_info_; + LanaiSelectionDAGInfo selection_dag_info_; +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_LANAISUBTARGET_H Index: lib/Target/Lanai/LanaiSubtarget.cpp =================================================================== --- lib/Target/Lanai/LanaiSubtarget.cpp +++ lib/Target/Lanai/LanaiSubtarget.cpp @@ -0,0 +1,50 @@ +//===- LanaiSubtarget.cpp - Lanai Subtarget Information -----------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Lanai specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#include "LanaiSubtarget.h" + +#include "Lanai.h" + +#define DEBUG_TYPE "lanai-subtarget" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "LanaiGenSubtargetInfo.inc" + +using namespace llvm; + +void LanaiSubtarget::anchor() {} + +void LanaiSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { + std::string CPUName = CPU; + if (CPUName.empty()) + CPUName = "generic"; + + ParseSubtargetFeatures(CPUName, FS); +} + +LanaiSubtarget &LanaiSubtarget::initializeSubtargetDependencies(StringRef CPU, + StringRef FS) { + initSubtargetFeatures(CPU, FS); + return *this; +} + +LanaiSubtarget::LanaiSubtarget(const Triple &TargetTriple, StringRef Cpu, + StringRef FeatureString, TargetMachine *TM, + const TargetOptions &Options, + Reloc::Model RelocationModel, + CodeModel::Model CodeModel, + CodeGenOpt::Level OptLevel) + : LanaiGenSubtargetInfo(TargetTriple, Cpu, FeatureString), + frame_lowering_(&initializeSubtargetDependencies(Cpu, FeatureString)), + instr_info_(), target_lowering_info_(TM, this), selection_dag_info_() {} Index: lib/Target/Lanai/LanaiTargetMachine.h =================================================================== --- lib/Target/Lanai/LanaiTargetMachine.h +++ lib/Target/Lanai/LanaiTargetMachine.h @@ -0,0 +1,54 @@ +//===-- LanaiTargetMachine.h - Define TargetMachine 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 declares the Lanai specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_LANAITARGETMACHINE_H +#define LLVM_LIB_TARGET_LANAI_LANAITARGETMACHINE_H + +#include "LanaiFrameLowering.h" +#include "LanaiISelLowering.h" +#include "LanaiInstrInfo.h" +#include "LanaiSelectionDAGInfo.h" +#include "LanaiSubtarget.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class formatted_raw_ostream; + +class LanaiTargetMachine : public LLVMTargetMachine { + LanaiSubtarget Subtarget; + std::unique_ptr TLOF; + +public: + LanaiTargetMachine(const Target &TheTarget, const Triple &TargetTriple, + StringRef Cpu, StringRef FeatureString, + const TargetOptions &Options, Reloc::Model RelocationModel, + CodeModel::Model CodeModel, CodeGenOpt::Level OptLevel); + + const LanaiSubtarget * + getSubtargetImpl(const llvm::Function &Fn) const override { + return &Subtarget; + } + + TargetIRAnalysis getTargetIRAnalysis() override; + + // Pass Pipeline Configuration + TargetPassConfig *createPassConfig(PassManagerBase &pass_manager) override; + + TargetLoweringObjectFile *getObjFileLowering() const override { + return TLOF.get(); + } +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_LANAITARGETMACHINE_H Index: lib/Target/Lanai/LanaiTargetMachine.cpp =================================================================== --- lib/Target/Lanai/LanaiTargetMachine.cpp +++ lib/Target/Lanai/LanaiTargetMachine.cpp @@ -0,0 +1,115 @@ +//===-- LanaiTargetMachine.cpp - Define TargetMachine for Lanai ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements the info about Lanai target spec. +// +//===----------------------------------------------------------------------===// + +#include "LanaiTargetMachine.h" + +#include "Lanai.h" +#include "LanaiTargetObjectFile.h" +#include "LanaiTargetTransformInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +namespace llvm { +void initializeLanaiMemAluCombinerPass(PassRegistry &); +void initializeLanaiSetflagAluCombinerPass(PassRegistry &); +} // namespace llvm + +extern "C" void LLVMInitializeLanaiTarget() { + // Register the target. + RegisterTargetMachine registered_target(TheLanaiTarget); +} + +static std::string computeDataLayout(const Triple &TT) { + // Data layout (keep in sync with clang/lib/Basic/Targets.cpp) + return "E" // Big endian + "-m:e" // ELF name manging + "-p:32:32" // 32-bit pointers word aligned + "-i64:64" // 64 bit integers, 64 bit aligned + "-a:0:32" // 32 bit alignment of objects of aggregate type + "-n32" // 32 bit native integer width + "-S64"; // 64 bit natural stack alignment +} + +LanaiTargetMachine::LanaiTargetMachine(const Target &TheTarget, + const Triple &TargetTriple, + StringRef Cpu, StringRef FeatureString, + const TargetOptions &Options, + Reloc::Model RelocationModel, + CodeModel::Model CodeModel, + CodeGenOpt::Level OptLevel) + : LLVMTargetMachine(TheTarget, computeDataLayout(TargetTriple), + TargetTriple, Cpu, FeatureString, Options, + RelocationModel, CodeModel, OptLevel), + Subtarget(TargetTriple, Cpu, FeatureString, this, Options, + RelocationModel, CodeModel, OptLevel), + TLOF(new LanaiTargetObjectFile()) { + initAsmInfo(); +} + +TargetIRAnalysis LanaiTargetMachine::getTargetIRAnalysis() { + return TargetIRAnalysis([this](const Function &F) { + return TargetTransformInfo(LanaiTTIImpl(this, F)); + }); +} + +namespace { +// Lanai Code Generator Pass Configuration Options. +class LanaiPassConfig : public TargetPassConfig { +public: + LanaiPassConfig(LanaiTargetMachine *TM, PassManagerBase *PassManager) + : TargetPassConfig(TM, *PassManager) {} + + LanaiTargetMachine &getLanaiTargetMachine() const { + return getTM(); + } + + bool addInstSelector() override; + void addPreSched2() override; + void addPreEmitPass() override; +}; +} // namespace + +TargetPassConfig * +LanaiTargetMachine::createPassConfig(PassManagerBase &PassManager) { + return new LanaiPassConfig(this, &PassManager); +} + +// Install an instruction selector pass. +bool LanaiPassConfig::addInstSelector() { + addPass(createLanaiISelDag(getLanaiTargetMachine())); + return false; +} + +// Implemented by targets that want to run passes immediately before +// machine code is emitted. +void LanaiPassConfig::addPreEmitPass() { + addPass(createLanaiDelaySlotFillerPass(getLanaiTargetMachine())); +} + +// Run passes after prolog-epilog insertion and before the second instruction +// scheduling pass. +void LanaiPassConfig::addPreSched2() { + if (TM->getOptLevel() != CodeGenOpt::None) { + addPass(createLanaiMemAluCombinerPass()); + addPass(createLanaiSetflagAluCombinerPass()); + } + // Insert instruction to save the return address prior to a direct + // or indirect call. + addPass(createLanaiSaveReturnAddressPass()); +} Index: lib/Target/Lanai/LanaiTargetObjectFile.h =================================================================== --- lib/Target/Lanai/LanaiTargetObjectFile.h +++ lib/Target/Lanai/LanaiTargetObjectFile.h @@ -0,0 +1,48 @@ +//===-- LanaiTargetObjectFile.h - Lanai Object Info -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_LANAITARGETOBJECTFILE_H +#define LLVM_LIB_TARGET_LANAI_LANAITARGETOBJECTFILE_H + +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + +namespace llvm { +class LanaiTargetMachine; +class LanaiTargetObjectFile : public TargetLoweringObjectFileELF { + MCSection *SmallDataSection; + MCSection *SmallBSSSection; + const LanaiTargetMachine *TM; + +public: + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + + /// Return true if this global address should be placed into small data/bss + /// section. + bool isGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, + SectionKind Kind) const; + bool isGlobalInSmallSection(const GlobalValue *GV, + const TargetMachine &TM) const; + bool isGlobalInSmallSectionImpl(const GlobalValue *GV, + const TargetMachine &TM) const; + + MCSection *SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, + Mangler &Mang, + const TargetMachine &TM) const override; + + /// Return true if this constant should be placed into small data section. + bool isConstantInSmallSection(const DataLayout &DL, const Constant *CN, + const TargetMachine &TM) const; + + MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, + const Constant *C, + unsigned &Align) const override; +}; +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_LANAITARGETOBJECTFILE_H Index: lib/Target/Lanai/LanaiTargetObjectFile.cpp =================================================================== --- lib/Target/Lanai/LanaiTargetObjectFile.cpp +++ lib/Target/Lanai/LanaiTargetObjectFile.cpp @@ -0,0 +1,126 @@ +//===-- LanaiTargetObjectFile.cpp - Lanai Object Files --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LanaiTargetObjectFile.h" + +#include "LanaiSubtarget.h" +#include "LanaiTargetMachine.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ELF.h" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +static cl::opt SSThreshold( + "lanai-ssection-threshold", cl::Hidden, + cl::desc("Small data and bss section threshold size (default=0)"), + cl::init(0)); + +void LanaiTargetObjectFile::Initialize(MCContext &Ctx, + const TargetMachine &TM) { + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + InitializeELF(TM.Options.UseInitArray); + + SmallDataSection = getContext().getELFSection( + ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); + SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC); + + this->TM = &static_cast(TM); +} + +// A address must be loaded from a small section if its size is less than the +// small section size threshold. Data in this section must be addressed using +// gp_rel operator. +static bool isInSmallSection(uint64_t Size) { + // gcc has traditionally not treated zero-sized objects as small data, so this + // is effectively part of the ABI. + return Size > 0 && Size <= SSThreshold; +} + +// Return true if this global address should be placed into small data/bss +// section. +bool LanaiTargetObjectFile::isGlobalInSmallSection( + const GlobalValue *GV, const TargetMachine &TM) const { + // We first check the case where global is a declaration, because finding + // section kind using getKindForGlobal() is only allowed for global + // definitions. + if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) + return isGlobalInSmallSectionImpl(GV, TM); + + return isGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM)); +} + +// Return true if this global address should be placed into small data/bss +// section. +bool LanaiTargetObjectFile::isGlobalInSmallSection(const GlobalValue *GV, + const TargetMachine &TM, + SectionKind Kind) const { + return (isGlobalInSmallSectionImpl(GV, TM) && + (Kind.isData() || Kind.isBSS() || Kind.isCommon())); +} + +// Return true if this global address should be placed into small data/bss +// section. This method does all the work, except for checking the section +// kind. +bool LanaiTargetObjectFile::isGlobalInSmallSectionImpl( + const GlobalValue *GV, const TargetMachine &TM) const { + // Only global variables, not functions. + const GlobalVariable *GVA = dyn_cast(GV); + if (!GVA) + return false; + + if (GV->hasLocalLinkage()) + return false; + + if (((GV->hasExternalLinkage() && GV->isDeclaration()) || + GV->hasCommonLinkage())) + return false; + + Type *Ty = GV->getType()->getElementType(); + return isInSmallSection( + GV->getParent()->getDataLayout().getTypeAllocSize(Ty)); +} + +MCSection * +LanaiTargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV, + SectionKind Kind, Mangler &Mang, + const TargetMachine &TM) const { + // Handle Small Section classification here. + if (Kind.isBSS() && isGlobalInSmallSection(GV, TM, Kind)) + return SmallBSSSection; + if (Kind.isData() && isGlobalInSmallSection(GV, TM, Kind)) + return SmallDataSection; + + // Otherwise, we work the same as ELF. + return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang, + TM); +} + +/// Return true if this constant should be placed into small data section. +bool LanaiTargetObjectFile::isConstantInSmallSection( + const DataLayout &DL, const Constant *CN, const TargetMachine &TM) const { + return isInSmallSection(DL.getTypeAllocSize(CN->getType())); +} + +MCSection *LanaiTargetObjectFile::getSectionForConstant(const DataLayout &DL, + SectionKind Kind, + const Constant *C, + unsigned &Align) const { + if (isConstantInSmallSection(DL, C, *TM)) + return SmallDataSection; + + // Otherwise, we work the same as ELF. + return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align); +} Index: lib/Target/Lanai/LanaiTargetTransformInfo.h =================================================================== --- lib/Target/Lanai/LanaiTargetTransformInfo.h +++ lib/Target/Lanai/LanaiTargetTransformInfo.h @@ -0,0 +1,87 @@ +//===-- LanaiTargetTransformInfo.h - Lanai specific TTI ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file a TargetTransformInfo::Concept conforming object specific to the +// Lanai target machine. It uses the target's detailed information to +// provide more precise answers to certain TTI queries, while letting the +// target independent and default TTI implementations handle the rest. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_LANAITARGETTRANSFORMINFO_H +#define LLVM_LIB_TARGET_LANAI_LANAITARGETTRANSFORMINFO_H + +#include "Lanai.h" +#include "LanaiSubtarget.h" +#include "LanaiTargetMachine.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/BasicTTIImpl.h" +#include "llvm/Target/TargetLowering.h" + +namespace llvm { +class LanaiTTIImpl : public BasicTTIImplBase { + typedef BasicTTIImplBase BaseT; + typedef TargetTransformInfo TTI; + friend BaseT; + + const LanaiSubtarget *ST; + const LanaiTargetLowering *TLI; + + const LanaiSubtarget *getST() const { return ST; } + const LanaiTargetLowering *getTLI() const { return TLI; } + +public: + explicit LanaiTTIImpl(const LanaiTargetMachine *TM, const Function &F) + : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), + TLI(ST->getTargetLowering()) {} + + LanaiTTIImpl(const LanaiTTIImpl &Arg) + : BaseT(static_cast(Arg)), ST(Arg.ST), TLI(Arg.TLI) {} + LanaiTTIImpl(LanaiTTIImpl &&Arg) + : BaseT(std::move(static_cast(Arg))), ST(std::move(Arg.ST)), + TLI(std::move(Arg.TLI)) {} + + bool shouldBuildLookupTables() const { return false; } + + TargetTransformInfo::PopcntSupportKind getPopcntSupport(unsigned TyWidth) { + if (TyWidth == 32) + return TTI::PSK_FastHardware; + return TTI::PSK_Software; + } + + unsigned getArithmeticInstrCost( + unsigned Opcode, Type *Ty, + TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue, + TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue, + TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None, + TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None) { + int ISD = TLI->InstructionOpcodeToISD(Opcode); + + switch (ISD) { + default: + return BaseT::getArithmeticInstrCost(Opcode, Ty, Opd1Info, Opd2Info, + Opd1PropInfo, Opd2PropInfo); + case ISD::MUL: + case ISD::SDIV: + case ISD::UDIV: + case ISD::UREM: + // This increases the cost associated with multiplication and division + // to 64 times what the baseline arithmetic cost is. The arithmetic + // instruction cost was arbitrarily chosen to reduce the desirability + // of emitting arithmetic instructions that are emulated in software. + // TODO: Investigate the performance impact given specialized lowerings. + return 64 * BaseT::getArithmeticInstrCost(Opcode, Ty, Opd1Info, Opd2Info, + Opd1PropInfo, Opd2PropInfo); + } + } +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_LANAITARGETTRANSFORMINFO_H Index: lib/Target/Lanai/MCTargetDesc/CMakeLists.txt =================================================================== --- lib/Target/Lanai/MCTargetDesc/CMakeLists.txt +++ lib/Target/Lanai/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,8 @@ +add_llvm_library(LLVMLanaiMCTargetDesc + LanaiAsmBackend.cpp + LanaiELFObjectWriter.cpp + LanaiMCAsmInfo.cpp + LanaiMCCodeEmitter.cpp + LanaiMCExpr.cpp + LanaiMCTargetDesc.cpp +) Index: lib/Target/Lanai/MCTargetDesc/LLVMBuild.txt =================================================================== --- lib/Target/Lanai/MCTargetDesc/LLVMBuild.txt +++ lib/Target/Lanai/MCTargetDesc/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===-- ./lib/Target/Lanai/MCTargetDesc/LLVMBuild.txt -----------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = LanaiMCTargetDesc +parent = Lanai +required_libraries = LanaiInfo LanaiInstPrinter MC Support +add_to_library_groups = Lanai Index: lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp +++ lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp @@ -0,0 +1,171 @@ +//===-- LanaiAsmBackend.cpp - Lanai Assembler Backend ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LanaiFixupKinds.h" +#include "MCTargetDesc/LanaiMCTargetDesc.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +// Prepare value for the target space +static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { + switch (Kind) { + case FK_Data_1: + case FK_Data_2: + case FK_Data_4: + case FK_Data_8: + return Value; + case Lanai::FIXUP_LANAI_21: + case Lanai::FIXUP_LANAI_21_F: + case Lanai::FIXUP_LANAI_25: + case Lanai::FIXUP_LANAI_32: + case Lanai::FIXUP_LANAI_HI16: + case Lanai::FIXUP_LANAI_LO16: + return Value; + default: + llvm_unreachable("Unknown fixup kind!"); + } +} + +namespace { +class LanaiAsmBackend : public MCAsmBackend { + Triple::OSType OSType; + +public: + LanaiAsmBackend(const Target &T, Triple::OSType OST) + : MCAsmBackend(), OSType(OST) {} + + void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value, bool IsPCRel) const override; + + MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; + + // No instruction requires relaxation + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + return false; + } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; + + unsigned getNumFixupKinds() const override { + return Lanai::NumTargetFixupKinds; + } + + bool mayNeedRelaxation(const MCInst &Inst) const override { return false; } + + void relaxInstruction(const MCInst &Inst, MCInst &Res) const override {} + + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; +}; + +bool LanaiAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { + if ((Count % 4) != 0) + return false; + + for (uint64_t i = 0; i < Count; i += 4) + OW->write32(0x15000000); + + return true; +} + +void LanaiAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, + unsigned DataSize, uint64_t Value, + bool IsPCRel) const { + MCFixupKind Kind = Fixup.getKind(); + Value = adjustFixupValue(static_cast(Kind), Value); + + if (!Value) + return; // This value doesn't change the encoding + + // Where in the object and where the number of bytes that need + // fixing up + unsigned Offset = Fixup.getOffset(); + unsigned NumBytes = (getFixupKindInfo(Kind).TargetSize + 7) / 8; + unsigned FullSize = 4; + + // Grab current value, if any, from bits. + uint64_t CurVal = 0; + + // Load instruction and apply value + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = (FullSize - 1 - i); + CurVal |= static_cast(static_cast(Data[Offset + Idx])) + << (i * 8); + } + + uint64_t Mask = + (static_cast(-1) >> (64 - getFixupKindInfo(Kind).TargetSize)); + CurVal |= Value & Mask; + + // Write out the fixed up bytes back to the code/data bits. + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = (FullSize - 1 - i); + Data[Offset + Idx] = static_cast((CurVal >> (i * 8)) & 0xff); + } +} + +MCObjectWriter * +LanaiAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { + return createLanaiELFObjectWriter(OS, + MCELFObjectTargetWriter::getOSABI(OSType)); +} + +const MCFixupKindInfo & +LanaiAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { + static const MCFixupKindInfo Infos[Lanai::NumTargetFixupKinds] = { + // This table *must* be in same the order of fixup_* kinds in + // LanaiFixupKinds.h. + // Note: The number of bits indicated here are assumed to be contiguous. + // This does not hold true for LANAI_21 and LANAI_21_F which are applied + // to bits 0x7cffff and 0x7cfffc, respectively. Since the 'bits' counts + // here are used only for cosmetic purposes, we set the size to 16 bits + // for these 21-bit relocation as llvm/lib/MC/MCAsmStreamer.cpp checks + // no bits are set in the fixup range. + // + // name offset bits flags + {"FIXUP_LANAI_NONE", 0, 32, 0}, + {"FIXUP_LANAI_21", 16, 16 /*21*/, 0}, + {"FIXUP_LANAI_21_F", 16, 16 /*21*/, 0}, + {"FIXUP_LANAI_25", 7, 25, 0}, + {"FIXUP_LANAI_32", 0, 32, 0}, + {"FIXUP_LANAI_HI16", 16, 16, 0}, + {"FIXUP_LANAI_LO16", 16, 16, 0}}; + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; +} + +} // namespace + +MCAsmBackend *llvm::createLanaiAsmBackend(const Target &T, + const MCRegisterInfo &MRI, + const Triple &TheTriple, + StringRef CPU) { + if (TheTriple.isOSDarwin()) + assert(0 && "Mac not supported on Lanai"); + + if (TheTriple.isOSWindows()) + assert(0 && "Windows not supported on Lanai"); + + return new LanaiAsmBackend(T, TheTriple.getOS()); +} Index: lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h +++ lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h @@ -0,0 +1,145 @@ +//===-- LanaiBaseInfo.h - Top level definitions for Lanai MC ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains small standalone helper functions and enum definitions for +// the Lanai target useful for the compiler back-end and the MC libraries. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIBASEINFO_H +#define LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIBASEINFO_H + +#include "LanaiMCTargetDesc.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + +// LanaiII - This namespace holds all of the target specific flags that +// instruction info tracks. +// +namespace LanaiII { +// Target Operand Flag enum. +enum TOF { + //===------------------------------------------------------------------===// + // Lanai Specific MachineOperand flags. + MO_NO_FLAG, + + // MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol + // address. + MO_ABS_HI, + MO_ABS_LO, + + // MO_PIC_BASE_OFFSET - On a symbol operand this indicates that the + // immediate should get the value of the symbol minus the PIC base label: + // SYMBOL_LABEL - PICBASELABEL + MO_PIC_BASE_OFFSET, + + // MO_GOT - On a symbol operand this indicates that the immediate is the + // offset to the GOT entry for the symbol name from the base of the GOT. + MO_GOT, + + // MO_GOTOFFHI/MO_GOTOFFLO - On a symbol operand this indicates that the + // immediate is the offset to the location of the symbol name from the + // base of the GOT. + MO_GOTOFFHI, + MO_GOTOFFLO, + + // MO_GOTPCHI/MO_GOTPCLO - On a symbol operand this indicates that + // the immediate is an offset to the GOT entry for the symbol name + // from the current code location. + MO_GOTPCHI, + MO_GOTPCLO, + + // MO_PLT - On a symbol operand this indicates that the immediate is + // offset to the PLT entry of symbol name from the current code location. + MO_PLT +}; +} // namespace LanaiII + +static inline unsigned getLanaiRegisterNumbering(unsigned Reg) { + switch (Reg) { + case Lanai::R0: + return 0; + case Lanai::R1: + return 1; + case Lanai::R2: + case Lanai::PC: + return 2; + case Lanai::R3: + return 3; + case Lanai::R4: + case Lanai::SP: + return 4; + case Lanai::R5: + case Lanai::FP: + return 5; + case Lanai::R6: + return 6; + case Lanai::R7: + return 7; + case Lanai::R8: + case Lanai::RV: + return 8; + case Lanai::R9: + return 9; + case Lanai::R10: + case Lanai::RR1: + return 10; + case Lanai::R11: + case Lanai::RR2: + return 11; + case Lanai::R12: + return 12; + case Lanai::R13: + return 13; + case Lanai::R14: + return 14; + case Lanai::R15: + case Lanai::RCA: + return 15; + case Lanai::R16: + return 16; + case Lanai::R17: + return 17; + case Lanai::R18: + return 18; + case Lanai::R19: + return 19; + case Lanai::R20: + return 20; + case Lanai::R21: + return 21; + case Lanai::R22: + return 22; + case Lanai::R23: + return 23; + case Lanai::R24: + return 24; + case Lanai::R25: + return 25; + case Lanai::R26: + return 26; + case Lanai::R27: + return 27; + case Lanai::R28: + return 28; + case Lanai::R29: + return 29; + case Lanai::R30: + return 30; + case Lanai::R31: + return 31; + default: + llvm_unreachable("Unknown register number!"); + } +} +} // namespace llvm +#endif // LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIBASEINFO_H Index: lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp +++ lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp @@ -0,0 +1,95 @@ +//===-- LanaiELFObjectWriter.cpp - Lanai ELF Writer -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/LanaiBaseInfo.h" +#include "MCTargetDesc/LanaiFixupKinds.h" +#include "MCTargetDesc/LanaiMCTargetDesc.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { +class LanaiELFObjectWriter : public MCELFObjectTargetWriter { +public: + explicit LanaiELFObjectWriter(uint8_t OSABI); + + ~LanaiELFObjectWriter() override; + +protected: + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const override; + bool needsRelocateWithSymbol(const MCSymbol &SD, + unsigned Type) const override; +}; +} // namespace + +LanaiELFObjectWriter::LanaiELFObjectWriter(uint8_t OSABI) + : MCELFObjectTargetWriter(/*Is64Bit=*/false, OSABI, ELF::EM_LANAI, + /*HasRelocationAddend=*/true) {} + +LanaiELFObjectWriter::~LanaiELFObjectWriter() {} + +unsigned LanaiELFObjectWriter::getRelocType(MCContext &Ctx, + const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + unsigned Type; + unsigned Kind = static_cast(Fixup.getKind()); + switch (Kind) { + case Lanai::FIXUP_LANAI_21: + Type = ELF::R_LANAI_21; + break; + case Lanai::FIXUP_LANAI_21_F: + Type = ELF::R_LANAI_21_F; + break; + case Lanai::FIXUP_LANAI_25: + Type = ELF::R_LANAI_25; + break; + case Lanai::FIXUP_LANAI_32: + case FK_Data_4: + Type = ELF::R_LANAI_32; + break; + case Lanai::FIXUP_LANAI_HI16: + Type = ELF::R_LANAI_HI16; + break; + case Lanai::FIXUP_LANAI_LO16: + Type = ELF::R_LANAI_LO16; + break; + case Lanai::FIXUP_LANAI_NONE: + Type = ELF::R_LANAI_NONE; + break; + + default: + llvm_unreachable("Invalid fixup kind!"); + } + return Type; +} + +bool LanaiELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &SD, + unsigned Type) const { + switch (Type) { + case ELF::R_LANAI_21: + case ELF::R_LANAI_21_F: + case ELF::R_LANAI_25: + case ELF::R_LANAI_32: + case ELF::R_LANAI_HI16: + return true; + default: + return false; + } +} + +MCObjectWriter *llvm::createLanaiELFObjectWriter(raw_pwrite_stream &OS, + uint8_t OSABI) { + MCELFObjectTargetWriter *MOTW = new LanaiELFObjectWriter(OSABI); + return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); +} Index: lib/Target/Lanai/MCTargetDesc/LanaiFixupKinds.h =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiFixupKinds.h +++ lib/Target/Lanai/MCTargetDesc/LanaiFixupKinds.h @@ -0,0 +1,43 @@ +//===-- LanaiFixupKinds.h - Lanai Specific Fixup Entries --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIFIXUPKINDS_H +#define LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIFIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +namespace llvm { +namespace Lanai { +// Although most of the current fixup types reflect a unique relocation +// one can have multiple fixup types for a given relocation and thus need +// to be uniquely named. +// +// This table *must* be in the save order of +// MCFixupKindInfo Infos[Lanai::NumTargetFixupKinds] +// in LanaiAsmBackend.cpp. +// +enum Fixups { + // Results in R_Lanai_NONE + FIXUP_LANAI_NONE = FirstTargetFixupKind, + + FIXUP_LANAI_21, // 21-bit symbol relocation + FIXUP_LANAI_21_F, // 21-bit symbol relocation, last two bits masked to 0 + FIXUP_LANAI_25, // 25-bit branch targets + FIXUP_LANAI_32, // general 32-bit relocation + FIXUP_LANAI_HI16, // upper 16-bits of a symbolic relocation + FIXUP_LANAI_LO16, // lower 16-bits of a symbolic relocation + + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind +}; +} // namespace Lanai +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIFIXUPKINDS_H Index: lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.h =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.h +++ lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.h @@ -0,0 +1,32 @@ +//=====-- LanaiMCAsmInfo.h - Lanai asm properties -----------*- C++ -*--====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the LanaiMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCASMINFO_H +#define LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCASMINFO_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCAsmInfoELF.h" + +namespace llvm { +class Triple; + +class LanaiMCAsmInfo : public MCAsmInfoELF { + void anchor() override; + +public: + explicit LanaiMCAsmInfo(const Triple &TheTriple); +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCASMINFO_H Index: lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.cpp =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.cpp +++ lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.cpp @@ -0,0 +1,43 @@ +//===-- LanaiMCAsmInfo.cpp - Lanai asm properties -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the LanaiMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "LanaiMCAsmInfo.h" + +#include "llvm/ADT/Triple.h" + +using namespace llvm; + +void LanaiMCAsmInfo::anchor() {} + +LanaiMCAsmInfo::LanaiMCAsmInfo(const Triple &TheTriple) { + IsLittleEndian = false; + PrivateGlobalPrefix = ".L"; + WeakRefDirective = "\t.weak\t"; + ExceptionsType = ExceptionHandling::DwarfCFI; + + // Lanai assembly requires ".section" before ".bss" + UsesELFSectionDirectiveForBSS = true; + + // Use the integrated assembler instead of system one. + UseIntegratedAssembler = true; + + // Use '!' as comment string to correspond with old toolchain. + CommentString = "!"; + + // Target supports emission of debugging information. + SupportsDebugInformation = true; + + // Set the instruction alignment. Currently used only for address adjustment + // in dwarf generation. + MinInstAlignment = 4; +} Index: lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp +++ lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp @@ -0,0 +1,346 @@ +//===-- LanaiMCCodeEmitter.cpp - Convert Lanai code to machine code -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the LanaiMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#include "Lanai.h" +#include "MCTargetDesc/LanaiBaseInfo.h" +#include "MCTargetDesc/LanaiFixupKinds.h" +#include "MCTargetDesc/LanaiMCExpr.h" +#include "MCTargetDesc/LanaiMCTargetDesc.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "mccodeemitter" + +STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); + +namespace llvm { +namespace { +class LanaiMCCodeEmitter : public MCCodeEmitter { + LanaiMCCodeEmitter(const LanaiMCCodeEmitter &); // DO NOT IMPLEMENT + void operator=(const LanaiMCCodeEmitter &); // DO NOT IMPLEMENT + const MCInstrInfo &InstrInfo; + MCContext &Context; + +public: + LanaiMCCodeEmitter(const MCInstrInfo &MCII, MCContext &C) + : InstrInfo(MCII), Context(C) {} + + ~LanaiMCCodeEmitter() override {} + + // The functions below are called by TableGen generated functions for getting + // the binary encoding of instructions/opereands. + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &Inst, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const; + + // getMachineOpValue - Return binary encoding of operand. If the machine + // operand requires relocation, record the relocation and return zero. + unsigned getMachineOpValue(const MCInst &Inst, const MCOperand &MCOp, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const; + + unsigned getRiMemoryOpValue(const MCInst &Inst, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const; + + unsigned getRrMemoryOpValue(const MCInst &Inst, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const; + + unsigned getSplsOpValue(const MCInst &Inst, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const; + + unsigned getNeg6OpValue(const MCInst &Inst, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const; + + unsigned getBranchTargetOpValue(const MCInst &Inst, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const; + + unsigned getCallTargetOpValue(const MCInst &Inst, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const; + + void encodeInstruction(const MCInst &Inst, raw_ostream &Ostream, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const override; + + unsigned adjustPqBitsRmAndRrm(const MCInst &Inst, unsigned Value, + const MCSubtargetInfo &STI) const; + + unsigned adjustPqBitsSpls(const MCInst &Inst, unsigned Value, + const MCSubtargetInfo &STI) const; +}; + +Lanai::Fixups FixupKind(const MCExpr *Expr) { + if (isa(Expr)) + return Lanai::FIXUP_LANAI_21; + if (const LanaiMCExpr *McExpr = dyn_cast(Expr)) { + LanaiMCExpr::VariantKind ExprKind = McExpr->getKind(); + switch (ExprKind) { + case LanaiMCExpr::VK_Lanai_None: + return Lanai::FIXUP_LANAI_21; + case LanaiMCExpr::VK_Lanai_ABS_HI: + return Lanai::FIXUP_LANAI_HI16; + case LanaiMCExpr::VK_Lanai_ABS_LO: + return Lanai::FIXUP_LANAI_LO16; + } + } + return Lanai::Fixups(0); +} + +// getMachineOpValue - Return binary encoding of operand. If the machine +// operand requires relocation, record the relocation and return zero. +unsigned LanaiMCCodeEmitter::getMachineOpValue( + const MCInst &Inst, const MCOperand &MCOp, SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const { + if (MCOp.isReg()) + return getLanaiRegisterNumbering(MCOp.getReg()); + if (MCOp.isImm()) + return static_cast(MCOp.getImm()); + + // MCOp must be an expression + assert(MCOp.isExpr()); + const MCExpr *Expr = MCOp.getExpr(); + + // Extract the symbolic reference side of a binary expression. + if (Expr->getKind() == MCExpr::Binary) { + const MCBinaryExpr *BinaryExpr = static_cast(Expr); + Expr = BinaryExpr->getLHS(); + } + + assert(isa(Expr) || Expr->getKind() == MCExpr::SymbolRef); + // Push fixup (all info is contained within) + Fixups.push_back( + MCFixup::create(0, MCOp.getExpr(), MCFixupKind(FixupKind(Expr)))); + return 0; +} + +// Helper function to adjust P and Q bits on load and store instructions. +unsigned adjustPqBits(const MCInst &Inst, unsigned Value, unsigned PBitShift, + unsigned QBitShift) { + const MCOperand AluOp = Inst.getOperand(3); + unsigned AluCode = AluOp.getImm(); + + // Set the P bit to one iff the immediate is nonzero and not a post-op + // instruction. + const MCOperand Op2 = Inst.getOperand(2); + Value &= ~(1 << PBitShift); + if (!LPAC::isPostOp(AluCode) && + ((Op2.isImm() && Op2.getImm() != 0) || + (Op2.isReg() && Op2.getReg() != Lanai::R0) || (Op2.isExpr()))) { + Value |= (1 << PBitShift); + } + + // Set the Q bit to one iff it is a post- or pre-op instruction. + assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg() && + "Expected register operand."); + Value &= ~(1 << QBitShift); + if (LPAC::modifiesOp(AluCode) && + ((Op2.isImm() && Op2.getImm() != 0) || + (Op2.isReg() && Op2.getReg() != Lanai::R0))) { + Value |= (1 << QBitShift); + } + + return Value; +} + +unsigned +LanaiMCCodeEmitter::adjustPqBitsRmAndRrm(const MCInst &Inst, unsigned Value, + const MCSubtargetInfo &STI) const { + return adjustPqBits(Inst, Value, 17, 16); +} + +unsigned +LanaiMCCodeEmitter::adjustPqBitsSpls(const MCInst &Inst, unsigned Value, + const MCSubtargetInfo &STI) const { + return adjustPqBits(Inst, Value, 11, 10); +} + +void LanaiMCCodeEmitter::encodeInstruction( + const MCInst &Inst, raw_ostream &Ostream, SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const { + // Get instruction encoding and emit it + unsigned Value = getBinaryCodeForInstr(Inst, Fixups, SubtargetInfo); + ++MCNumEmitted; // Keep track of the number of emitted insns. + + // Emit bytes in big-endian + for (int i = (4 - 1) * 8; i >= 0; i -= 8) + Ostream << static_cast((Value >> i) & 0xff); +} + +// Encode Lanai Memory Operand +unsigned LanaiMCCodeEmitter::getRiMemoryOpValue( + const MCInst &Inst, unsigned OpNo, SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const { + unsigned Encoding; + const MCOperand Op1 = Inst.getOperand(OpNo + 0); + const MCOperand Op2 = Inst.getOperand(OpNo + 1); + const MCOperand AluOp = Inst.getOperand(OpNo + 2); + + assert(Op1.isReg() && "First operand is not register."); + assert((Op2.isImm() || Op2.isExpr()) && + "Second operand is neither an immediate nor an expression."); + assert((LPAC::getAluOp(AluOp.getImm()) == LPAC::ADD) && + "Register immediate only supports addition operator"); + + Encoding = (getLanaiRegisterNumbering(Op1.getReg()) << 18); + if (Op2.isImm()) { + assert(isInt<16>(Op2.getImm()) && + "Constant value truncated (limited to 16-bit)"); + + Encoding |= (Op2.getImm() & 0xffff); + if (Op2.getImm() != 0) { + if (LPAC::isPreOp(AluOp.getImm())) + Encoding |= (0x3 << 16); + if (LPAC::isPostOp(AluOp.getImm())) + Encoding |= (0x1 << 16); + } + } else { + getMachineOpValue(Inst, Op2, Fixups, SubtargetInfo); + } + + return Encoding; +} + +unsigned LanaiMCCodeEmitter::getRrMemoryOpValue( + const MCInst &Inst, unsigned OpNo, SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const { + unsigned Encoding; + const MCOperand Op1 = Inst.getOperand(OpNo + 0); + const MCOperand Op2 = Inst.getOperand(OpNo + 1); + const MCOperand AluMCOp = Inst.getOperand(OpNo + 2); + + assert(Op1.isReg() && "First operand is not register."); + Encoding = (getLanaiRegisterNumbering(Op1.getReg()) << 15); + assert(Op2.isReg() && "Second operand is not register."); + Encoding |= (getLanaiRegisterNumbering(Op2.getReg()) << 10); + + assert(AluMCOp.isImm() && "Third operator is not immediate."); + // Set BBB + unsigned AluOp = AluMCOp.getImm(); + Encoding |= LPAC::encodeLanaiAluCode(AluOp) << 5; + // Set P and Q + if (LPAC::isPreOp(AluOp)) + Encoding |= (0x3 << 8); + if (LPAC::isPostOp(AluOp)) + Encoding |= (0x1 << 8); + // Set JJJJ + switch (LPAC::getAluOp(AluOp)) { + case LPAC::SHL: + case LPAC::SRL: + Encoding |= 0x10; + break; + case LPAC::SRA: + Encoding |= 0x18; + break; + default: + break; + } + + return Encoding; +} + +unsigned +LanaiMCCodeEmitter::getSplsOpValue(const MCInst &Inst, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const { + unsigned Encoding; + const MCOperand Op1 = Inst.getOperand(OpNo + 0); + const MCOperand Op2 = Inst.getOperand(OpNo + 1); + const MCOperand AluOp = Inst.getOperand(OpNo + 2); + + assert(Op1.isReg() && "First operand is not register."); + assert((Op2.isImm() || Op2.isExpr()) && + "Second operand is neither an immediate nor an expression."); + assert((LPAC::getAluOp(AluOp.getImm()) == LPAC::ADD) && + "Register immediate only supports addition operator"); + + Encoding = (getLanaiRegisterNumbering(Op1.getReg()) << 12); + if (Op2.isImm()) { + assert(isInt<10>(Op2.getImm()) && + "Constant value truncated (limited to 10-bit)"); + + Encoding |= (Op2.getImm() & 0x3ff); + if (Op2.getImm() != 0) { + if (LPAC::isPreOp(AluOp.getImm())) + Encoding |= (0x3 << 10); + if (LPAC::isPostOp(AluOp.getImm())) + Encoding |= (0x1 << 10); + } + } else { + getMachineOpValue(Inst, Op2, Fixups, SubtargetInfo); + } + + return Encoding; +} + +unsigned +LanaiMCCodeEmitter::getNeg6OpValue(const MCInst &Inst, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const { + const MCOperand Imm6 = Inst.getOperand(OpNo); + + assert(Imm6.isImm() && "Operand is not immediate."); + assert(isInt<6>(Imm6.getImm()) && + "Constant value truncated (limited to 6-bit)"); + return -Imm6.getImm(); +} + +unsigned LanaiMCCodeEmitter::getCallTargetOpValue( + const MCInst &Inst, unsigned OpNo, SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const { + const MCOperand &MCOp = Inst.getOperand(OpNo); + if (MCOp.isReg() || MCOp.isImm()) + return getMachineOpValue(Inst, MCOp, Fixups, SubtargetInfo); + + Fixups.push_back(MCFixup::create( + 0, MCOp.getExpr(), static_cast(Lanai::FIXUP_LANAI_25))); + + return 0; +} + +unsigned LanaiMCCodeEmitter::getBranchTargetOpValue( + const MCInst &Inst, unsigned OpNo, SmallVectorImpl &Fixups, + const MCSubtargetInfo &SubtargetInfo) const { + const MCOperand &MCOp = Inst.getOperand(OpNo); + if (MCOp.isReg() || MCOp.isImm()) + return getMachineOpValue(Inst, MCOp, Fixups, SubtargetInfo); + + Fixups.push_back(MCFixup::create( + 0, MCOp.getExpr(), static_cast(Lanai::FIXUP_LANAI_25))); + + return 0; +} + +#include "LanaiGenMCCodeEmitter.inc" +} // namespace +} // namespace llvm + +llvm::MCCodeEmitter * +llvm::createLanaiMCCodeEmitter(const MCInstrInfo &InstrInfo, + const MCRegisterInfo &MRI, MCContext &context) { + return new LanaiMCCodeEmitter(InstrInfo, context); +} Index: lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.h =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.h +++ lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.h @@ -0,0 +1,56 @@ +//===-- LanaiMCExpr.h - Lanai specific MC expression classes ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCEXPR_H +#define LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCEXPR_H + +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" + +namespace llvm { + +class LanaiMCExpr : public MCTargetExpr { +public: + enum VariantKind { VK_Lanai_None, VK_Lanai_ABS_HI, VK_Lanai_ABS_LO }; + +private: + const VariantKind Kind; + const MCExpr *Expr; + + explicit LanaiMCExpr(VariantKind Kind, const MCExpr *Expr) + : Kind(Kind), Expr(Expr) {} + +public: + static const LanaiMCExpr *create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx); + + // Returns the kind of this expression. + VariantKind getKind() const { return Kind; } + + // Returns the child of this expression. + const MCExpr *getSubExpr() const { return Expr; } + + void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; + bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, + const MCFixup *Fixup) const override; + void visitUsedExpr(MCStreamer &Streamer) const override; + MCFragment *findAssociatedFragment() const override { + return getSubExpr()->findAssociatedFragment(); + } + + // There are no TLS LanaiMCExprs at the moment. + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + + static bool classof(const MCExpr *E) { + return E->getKind() == MCExpr::Target; + } +}; +} // end namespace llvm + +#endif Index: lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.cpp =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.cpp +++ lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.cpp @@ -0,0 +1,60 @@ +//===-- LanaiMCExpr.cpp - Lanai specific MC expression classes ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LanaiMCExpr.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCStreamer.h" +using namespace llvm; + +#define DEBUG_TYPE "lanaimcexpr" + +const LanaiMCExpr *LanaiMCExpr::create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx) { + return new (Ctx) LanaiMCExpr(Kind, Expr); +} + +void LanaiMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { + if (Kind == VK_Lanai_None) { + Expr->print(OS, MAI); + return; + } + + switch (Kind) { + default: + llvm_unreachable("Invalid kind!"); + case VK_Lanai_ABS_HI: + OS << "hi"; + break; + case VK_Lanai_ABS_LO: + OS << "lo"; + break; + } + + OS << '('; + const MCExpr *Expr = getSubExpr(); + Expr->print(OS, MAI); + OS << ')'; +} + +void LanaiMCExpr::visitUsedExpr(MCStreamer &Streamer) const { + Streamer.visitUsedExpr(*getSubExpr()); +} + +bool LanaiMCExpr::evaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout, + const MCFixup *Fixup) const { + if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup)) + return false; + + Res = + MCValue::get(Res.getSymA(), Res.getSymB(), Res.getConstant(), getKind()); + + return true; +} Index: lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h +++ lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h @@ -0,0 +1,59 @@ +//===-- LanaiMCTargetDesc.h - Lanai Target Descriptions ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Lanai specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCTARGETDESC_H +#define LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCTARGETDESC_H + +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCInstrAnalysis; +class MCObjectWriter; +class MCRelocationInfo; +class MCSubtargetInfo; +class Target; +class Triple; +class StringRef; +class raw_pwrite_stream; + +extern Target TheLanaiTarget; + +MCCodeEmitter *createLanaiMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + MCContext &Ctx); + +MCAsmBackend *createLanaiAsmBackend(const Target &T, const MCRegisterInfo &MRI, + const Triple &TheTriple, StringRef CPU); + +MCObjectWriter *createLanaiELFObjectWriter(raw_pwrite_stream &OS, + uint8_t OSABI); +} // namespace llvm + +// Defines symbolic names for Lanai registers. This defines a mapping from +// register name to register number. +#define GET_REGINFO_ENUM +#include "LanaiGenRegisterInfo.inc" + +// Defines symbolic names for the Lanai instructions. +#define GET_INSTRINFO_ENUM +#include "LanaiGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "LanaiGenSubtargetInfo.inc" + +#endif // LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCTARGETDESC_H Index: lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp +++ lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp @@ -0,0 +1,170 @@ +//===-- LanaiMCTargetDesc.cpp - Lanai Target Descriptions -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Lanai specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "LanaiMCTargetDesc.h" + +#include "InstPrinter/LanaiInstPrinter.h" +#include "LanaiMCAsmInfo.h" +#include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCInstrAnalysis.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_MC_DESC +#include "LanaiGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "LanaiGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "LanaiGenRegisterInfo.inc" + +using namespace llvm; + +static MCInstrInfo *createLanaiMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitLanaiMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createLanaiMCRegisterInfo(const Triple &TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitLanaiMCRegisterInfo(X, Lanai::RCA, 0, 0, Lanai::PC); + return X; +} + +static MCSubtargetInfo * +createLanaiMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { + std::string CPUName = CPU; + if (CPUName.empty()) + CPUName = "generic"; + + return createLanaiMCSubtargetInfoImpl(TT, CPUName, FS); +} + +static MCCodeGenInfo *createLanaiMCCodeGenInfo(const Triple &TT, + Reloc::Model RM, + CodeModel::Model CM, + CodeGenOpt::Level OL) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + X->initMCCodeGenInfo(RM, CM, OL); + return X; +} + +static MCStreamer *createMCStreamer(const Triple &T, MCContext &Context, + MCAsmBackend &MAB, raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, bool RelaxAll) { + if (T.isOSDarwin()) { + llvm_unreachable("Lanai does not support Darwin MACH-O format"); + } + + if (T.isOSWindows()) { + llvm_unreachable("Lanai does not support Windows COFF format"); + } + + return createELFStreamer(Context, MAB, OS, Emitter, RelaxAll); +} + +static MCInstPrinter *createLanaiMCInstPrinter(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + if (SyntaxVariant == 0) + return new LanaiInstPrinter(MAI, MII, MRI); + return 0; +} + +MCRelocationInfo *createLanaiElfRelocation(const Triple &TheTriple, + MCContext &Ctx) { + return createMCRelocationInfo(TheTriple, Ctx); +} + +class LanaiMCInstrAnalysis : public MCInstrAnalysis { +public: + explicit LanaiMCInstrAnalysis(const MCInstrInfo *Info) + : MCInstrAnalysis(Info) {} + + bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, + uint64_t &Target) const override { + if (Inst.getNumOperands() == 0) { + return false; + } + + if (Info->get(Inst.getOpcode()).OpInfo[0].OperandType == + MCOI::OPERAND_PCREL) { + int64_t Imm = Inst.getOperand(0).getImm(); + Target = Addr + Size + Imm; + return true; + } else { + int64_t Imm = Inst.getOperand(0).getImm(); + + // Skip case where immediate is 0 as that occurs in file that isn't linked + // and the branch target inferred would be wrong. + if (Imm == 0) { + return false; + } + + Target = Imm; + return true; + } + } +}; + +static MCInstrAnalysis *createLanaiInstrAnalysis(const MCInstrInfo *Info) { + return new LanaiMCInstrAnalysis(Info); +} + +extern "C" void LLVMInitializeLanaiTargetMC() { + // Register the MC asm info. + RegisterMCAsmInfo X(TheLanaiTarget); + + // Register the MC codegen info. + TargetRegistry::RegisterMCCodeGenInfo(TheLanaiTarget, + createLanaiMCCodeGenInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(TheLanaiTarget, createLanaiMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(TheLanaiTarget, createLanaiMCRegisterInfo); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(TheLanaiTarget, + createLanaiMCSubtargetInfo); + + // Register the MC code emitter + TargetRegistry::RegisterMCCodeEmitter(TheLanaiTarget, + llvm::createLanaiMCCodeEmitter); + + // Register the ASM Backend + TargetRegistry::RegisterMCAsmBackend(TheLanaiTarget, createLanaiAsmBackend); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(TheLanaiTarget, + createLanaiMCInstPrinter); + + // Register the ELF streamer. + TargetRegistry::RegisterELFStreamer(TheLanaiTarget, createMCStreamer); + + // Register the MC relocation info. + TargetRegistry::RegisterMCRelocationInfo(TheLanaiTarget, + createLanaiElfRelocation); + + // Register the MC instruction analyzer. + TargetRegistry::RegisterMCInstrAnalysis(TheLanaiTarget, + createLanaiInstrAnalysis); +} Index: lib/Target/Lanai/TargetInfo/CMakeLists.txt =================================================================== --- lib/Target/Lanai/TargetInfo/CMakeLists.txt +++ lib/Target/Lanai/TargetInfo/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMLanaiInfo + LanaiTargetInfo.cpp + ) Index: lib/Target/Lanai/TargetInfo/LLVMBuild.txt =================================================================== --- lib/Target/Lanai/TargetInfo/LLVMBuild.txt +++ lib/Target/Lanai/TargetInfo/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/Lanai/TargetInfo/LLVMBuild.txt --------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = LanaiInfo +parent = Lanai +required_libraries = Support +add_to_library_groups = Lanai Index: lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp =================================================================== --- lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp +++ lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp @@ -0,0 +1,20 @@ +//===-- LanaiTargetInfo.cpp - Lanai Target Implementation -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Lanai.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +Target llvm::TheLanaiTarget; + +extern "C" void LLVMInitializeLanaiTargetInfo() { + RegisterTarget X(TheLanaiTarget, "lanai", "Lanai"); +} Index: test/CodeGen/Lanai/codemodel.ll =================================================================== --- test/CodeGen/Lanai/codemodel.ll +++ test/CodeGen/Lanai/codemodel.ll @@ -0,0 +1,30 @@ +; RUN: llc -march=lanai < %s | FileCheck %s +; RUN: llc -march=lanai < %s -code-model=small | FileCheck -check-prefix CHECK-SMALL %s + +@data = external global [0 x i32] ; <[0 x i32]*> [#uses=5] + +define i32 @foo() nounwind readonly { +entry: +; CHECK-SMALL-LABEL: foo: +; CHECK-SMALL: ld [data], %rv +; CHECK-LABEL: foo: +; CHECK: mov hi(data), %r[[REGISTER:[0-9]+]] +; CHECK: or %r[[REGISTER]], lo(data), %r[[REGISTER]] +; CHECK: ld 0[%r[[REGISTER]]], %rv + %0 = load i32, i32* getelementptr ([0 x i32], [0 x i32]* @data, i64 0, i64 0), align 4 ; [#uses=1] + ret i32 %0 +} + +define i32 @foo1() nounwind readonly { +entry: +; CHECK-SMALL-LABEL: foo1: +; CHECK-SMALL: mov data, %r[[REGISTER:[0-9]+]] +; CHECK-SMALL: ld 40[%r[[REGISTER]]], %rv +; CHECK-LABEL: foo1: +; CHECK: mov hi(data), %r[[REGISTER:[0-9]+]] +; CHECK: or %r[[REGISTER]], lo(data), %r[[REGISTER]] +; CHECK: ld 40[%r[[REGISTER]]], %rv + %0 = load i32, i32* getelementptr ([0 x i32], [0 x i32]* @data, i32 0, i64 10), align 4 ; [#uses=1] + ret i32 %0 +} + Index: test/CodeGen/Lanai/combined_alu_setcc.ll =================================================================== --- test/CodeGen/Lanai/combined_alu_setcc.ll +++ test/CodeGen/Lanai/combined_alu_setcc.ll @@ -0,0 +1,126 @@ +; RUN: llc < %s -march=lanai | FileCheck %s + +; Test the alu setcc combiner. + +; TODO: Enhance combiner to handle this case. This expands into: +; sub %r7, %r6, %r3 +; sub.f %r7, %r6, %r0 +; sel.eq %r18, %r3, %rv +; This is different from the pattern currently matched. If the lowered form had +; been sub.f %r3, 0, %r0 then it would have matched. + +; Function Attrs: norecurse nounwind readnone +define i32 @test0a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 { +entry: + %sub = sub i32 %b, %a + %cmp = icmp eq i32 %sub, 0 + %cond = select i1 %cmp, i32 %c, i32 %sub + ret i32 %cond +} +; CHECK-LABEL: test0a +; CHECK: sub.f %r7 +; CHECK: sel.eq + +; Function Attrs: norecurse nounwind readnone +define i32 @test0b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 { +entry: + %cmp = icmp eq i32 %b, %a + %cond = select i1 %cmp, i32 %c, i32 %b + ret i32 %cond +} +; CHECK-LABEL: test0b +; CHECK: sub.f %r7, %r6, %r0 +; CHECK-NEXT: sel.eq + +; Function Attrs: norecurse nounwind readnone +define i32 @test1a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 { +entry: + %sub = sub i32 %b, %a + %cmp = icmp slt i32 %sub, 0 + %cond = select i1 %cmp, i32 %c, i32 %d + ret i32 %cond +} +; CHECK-LABEL: test1a +; CHECK: sub.f %r7, %r6 +; CHECK-NEXT: sel.mi + +; Function Attrs: norecurse nounwind readnone +define i32 @test1b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 { +entry: + %sub = sub i32 %b, %a + %cmp = icmp slt i32 %sub, 0 + %cond = select i1 %cmp, i32 %c, i32 %d + ret i32 %cond +} +; CHECK-LABEL: test1b +; CHECK: sub.f %r7, %r6 +; CHECK-NEXT: sel.mi + +; Function Attrs: norecurse nounwind readnone +define i32 @test2a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 { +entry: + %sub = sub i32 %b, %a + %cmp = icmp sgt i32 %sub, -1 + %cond = select i1 %cmp, i32 %c, i32 %d + ret i32 %cond +} +; CHECK-LABEL: test2a +; CHECK: sub.f %r7, %r6 +; CHECK: sel.pl + +; Function Attrs: norecurse nounwind readnone +define i32 @test2b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 { +entry: + %sub = sub i32 %b, %a + %cmp = icmp sgt i32 %sub, -1 + %cond = select i1 %cmp, i32 %c, i32 %d + ret i32 %cond +} +; CHECK-LABEL: test2b +; CHECK: sub.f %r7, %r6 +; CHECK: sel.pl + +; Function Attrs: norecurse nounwind readnone +define i32 @test3(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 { +entry: + %sub = sub i32 %b, %a + %cmp = icmp slt i32 %sub, 1 + %cond = select i1 %cmp, i32 %c, i32 %d + ret i32 %cond +} + +; Function Attrs: norecurse nounwind readnone +define i32 @test4(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 { +entry: + %cmp = icmp ne i32 %a, 0 + %cmp1 = icmp ult i32 %a, %b + %or.cond = and i1 %cmp, %cmp1 + br i1 %or.cond, label %return, label %if.end + +if.end: ; preds = %entry + %cmp2 = icmp ne i32 %b, 0 + %cmp4 = icmp ult i32 %b, %c + %or.cond29 = and i1 %cmp2, %cmp4 + br i1 %or.cond29, label %return, label %if.end6 + +if.end6: ; preds = %if.end + %cmp7 = icmp ne i32 %c, 0 + %cmp9 = icmp ult i32 %c, %d + %or.cond30 = and i1 %cmp7, %cmp9 + br i1 %or.cond30, label %return, label %if.end11 + +if.end11: ; preds = %if.end6 + %cmp12 = icmp ne i32 %d, 0 + %cmp14 = icmp ult i32 %d, %a + %or.cond31 = and i1 %cmp12, %cmp14 + %b. = select i1 %or.cond31, i32 %b, i32 21 + ret i32 %b. + +return: ; preds = %if.end6, %if.end, %entry + %retval.0 = phi i32 [ %c, %entry ], [ %d, %if.end ], [ %a, %if.end6 ] + ret i32 %retval.0 +} +; CHECK-LABEL: test4 +; CHECK: and.f +; CHECK: and.f +; CHECK: and.f Index: test/CodeGen/Lanai/comparisons_i32.ll =================================================================== --- test/CodeGen/Lanai/comparisons_i32.ll +++ test/CodeGen/Lanai/comparisons_i32.ll @@ -0,0 +1,96 @@ +; RUN: llc < %s | FileCheck %s + +; Test that basic 32-bit integer comparison operations assemble as expected. + +target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "lanai" + +; CHECK-LABEL: eq_i32: +; CHECK: sub.f %r{{[0-9]+}}, %r{{[0-9]+}}, %r0 +; CHECK-NEXT: seq +define i32 @eq_i32(i32 %x, i32 %y) { + %a = icmp eq i32 %x, %y + %b = zext i1 %a to i32 + ret i32 %b +} + +; CHECK-LABEL: ne_i32: +; CHECK: sub.f %r{{[0-9]+}}, %r{{[0-9]+}}, %r0 +; CHECK-NEXT: sne +define i32 @ne_i32(i32 %x, i32 %y) { + %a = icmp ne i32 %x, %y + %b = zext i1 %a to i32 + ret i32 %b +} + +; CHECK-LABEL: slt_i32: +; CHECK: sub.f %r{{[0-9]+}}, %r{{[0-9]+}}, %r0 +; CHECK-NEXT: slt +define i32 @slt_i32(i32 %x, i32 %y) { + %a = icmp slt i32 %x, %y + %b = zext i1 %a to i32 + ret i32 %b +} + +; CHECK-LABEL: sle_i32: +; CHECK: sub.f %r{{[0-9]+}}, %r{{[0-9]+}}, %r0 +; CHECK-NEXT: sle +define i32 @sle_i32(i32 %x, i32 %y) { + %a = icmp sle i32 %x, %y + %b = zext i1 %a to i32 + ret i32 %b +} + +; CHECK-LABEL: ult_i32: +; CHECK: sub.f %r{{[0-9]+}}, %r{{[0-9]+}}, %r0 +; CHECK-NEXT: sult +define i32 @ult_i32(i32 %x, i32 %y) { + %a = icmp ult i32 %x, %y + %b = zext i1 %a to i32 + ret i32 %b +} + +; CHECK-LABEL: ule_i32: +; CHECK: sub.f %r{{[0-9]+}}, %r{{[0-9]+}}, %r0 +; CHECK-NEXT: sule +define i32 @ule_i32(i32 %x, i32 %y) { + %a = icmp ule i32 %x, %y + %b = zext i1 %a to i32 + ret i32 %b +} + +; CHECK-LABEL: sgt_i32: +; CHECK: sub.f %r{{[0-9]+}}, %r{{[0-9]+}}, %r0 +; CHECK-NEXT: sgt +define i32 @sgt_i32(i32 %x, i32 %y) { + %a = icmp sgt i32 %x, %y + %b = zext i1 %a to i32 + ret i32 %b +} + +; CHECK-LABEL: sge_i32: +; CHECK: sub.f %r{{[0-9]+}}, %r{{[0-9]+}}, %r0 +; CHECK-NEXT: sge +define i32 @sge_i32(i32 %x, i32 %y) { + %a = icmp sge i32 %x, %y + %b = zext i1 %a to i32 + ret i32 %b +} + +; CHECK-LABEL: ugt_i32: +; CHECK: sub.f %r{{[0-9]+}}, %r{{[0-9]+}}, %r0 +; CHECK-NEXT: sugt +define i32 @ugt_i32(i32 %x, i32 %y) { + %a = icmp ugt i32 %x, %y + %b = zext i1 %a to i32 + ret i32 %b +} + +; CHECK-LABEL: uge_i32: +; CHECK: sub.f %r{{[0-9]+}}, %r{{[0-9]+}}, %r0 +; CHECK-NEXT: suge +define i32 @uge_i32(i32 %x, i32 %y) { + %a = icmp uge i32 %x, %y + %b = zext i1 %a to i32 + ret i32 %b +} Index: test/CodeGen/Lanai/constant_multiply.ll =================================================================== --- test/CodeGen/Lanai/constant_multiply.ll +++ test/CodeGen/Lanai/constant_multiply.ll @@ -0,0 +1,107 @@ +; RUN: llc < %s | FileCheck %s + +; Test custom lowering for 32-bit integer multiplication. + +target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "lanai" + +; CHECK-LABEL: f6: +; CHECK: sh %r6, 0x1, %r{{[0-9]+}} +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @f6(i32 inreg %a) #0 { + %1 = mul nsw i32 %a, 6 + ret i32 %1 +} + +; CHECK-LABEL: f7: +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r6, %rv +define i32 @f7(i32 inreg %a) #0 { + %1 = mul nsw i32 %a, 7 + ret i32 %1 +} + +; CHECK-LABEL: f8: +; CHECK: sh %r6, 0x3, %rv +define i32 @f8(i32 inreg %a) #0 { + %1 = shl nsw i32 %a, 3 + ret i32 %1 +} + +; CHECK-LABEL: f9: +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: add %r{{[0-9]+}}, %r6, %rv +define i32 @f9(i32 inreg %a) #0 { + %1 = mul nsw i32 %a, 9 + ret i32 %1 +} + +; CHECK-LABEL: f10: +; CHECK: sh %r6, 0x1, %r{{[0-9]+}} +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: add %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @f10(i32 inreg %a) #0 { + %1 = mul nsw i32 %a, 10 + ret i32 %1 +} + +; CHECK-LABEL: f1280: +; CHECK: sh %r6, 0x8, %r{{[0-9]+}} +; CHECK: sh %r6, 0xa, %r{{[0-9]+}} +; CHECK: add %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @f1280(i32 inreg %a) #0 { + %1 = mul nsw i32 %a, 1280 + ret i32 %1 +} + +; CHECK-LABEL: fm6: +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sh %r6, 0x1, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @fm6(i32 inreg %a) #0 { + %1 = mul nsw i32 %a, -6 + ret i32 %1 +} + +; CHECK-LABEL: fm7: +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sub %r6, %r{{[0-9]+}}, %rv +define i32 @fm7(i32 inreg %a) #0 { + %1 = mul nsw i32 %a, -7 + ret i32 %1 +} + +; CHECK-LABEL: fm8: +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @fm8(i32 inreg %a) #0 { + %1 = mul nsw i32 %a, -8 + ret i32 %1 +} + +; CHECK-LABEL: fm9: +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r6, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @fm9(i32 inreg %a) #0 { + %1 = mul nsw i32 %a, -9 + ret i32 %1 +} + +; CHECK-LABEL: fm10: +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sh %r6, 0x1, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @fm10(i32 inreg %a) #0 { + %1 = mul nsw i32 %a, -10 + ret i32 %1 +} + +; CHECK-LABEL: h1: +; CHECK: __mulsi3 +define i32 @h1(i32 inreg %a) #0 { + %1 = mul i32 %a, -1431655765 + ret i32 %1 +} Index: test/CodeGen/Lanai/delay_filler.ll =================================================================== --- test/CodeGen/Lanai/delay_filler.ll +++ test/CodeGen/Lanai/delay_filler.ll @@ -0,0 +1,41 @@ +; RUN: llc -march=lanai < %s | FileCheck %s +; RUN: llc -march=lanai --lanai-nop-delay-filler < %s | \ +; RUN: FileCheck %s --check-prefix=NOP + +; CHECK: bt f +; CHECK-NEXT: or +; NOP: bt f +; NOP-NEXT: nop + +; ModuleID = 'delay_filler.c' +target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "lanai" + +; Function Attrs: nounwind +define i32 @g(i32 inreg %n) #0 { +entry: + %cmp5 = icmp sgt i32 %n, 0 + br i1 %cmp5, label %for.body.preheader, label %for.cond.cleanup + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %for.body + %call.lcssa = phi i32 [ %call, %for.body ] + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + %a.0.lcssa = phi i32 [ undef, %entry ], [ %call.lcssa, %for.cond.cleanup.loopexit ] + ret i32 %a.0.lcssa + +for.body: ; preds = %for.body.preheader, %for.body + %i.07 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] + %a.06 = phi i32 [ %call, %for.body ], [ undef, %for.body.preheader ] + %call = tail call i32 @f(i32 inreg %a.06) #2 + %inc = add nuw nsw i32 %i.07, 1 + %exitcond = icmp eq i32 %inc, %n + br i1 %exitcond, label %for.cond.cleanup.loopexit, label %for.body +} + +declare i32 @f(i32 inreg) #1 + Index: test/CodeGen/Lanai/i32.ll =================================================================== --- test/CodeGen/Lanai/i32.ll +++ test/CodeGen/Lanai/i32.ll @@ -0,0 +1,145 @@ +; RUN: llc < %s -asm-verbose=false | FileCheck %s + +; Test that basic 32-bit integer operations assemble as expected. + +target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "lanai" + +; Function Attrs: nounwind readnone +declare i32 @llvm.ctpop.i32(i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.ctlz.i32(i32, i1) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.cttz.i32(i32, i1) #1 + +; CHECK-LABEL: add32: +; CHECK: add %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @add32(i32 %x, i32 %y) { + %a = add i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: sub32: +; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @sub32(i32 %x, i32 %y) { + %a = sub i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: mul32: +; CHECK: bt __mulsi3 +define i32 @mul32(i32 %x, i32 %y) { + %a = mul i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: sdiv32: +; CHECK: bt __divsi3 +define i32 @sdiv32(i32 %x, i32 %y) { + %a = sdiv i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: udiv32: +; CHECK: bt __udivsi3 +define i32 @udiv32(i32 %x, i32 %y) { + %a = udiv i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: srem32: +; CHECK: bt __modsi3 +define i32 @srem32(i32 %x, i32 %y) { + %a = srem i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: urem32: +; CHECK: bt __umodsi3 +define i32 @urem32(i32 %x, i32 %y) { + %a = urem i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: and32: +; CHECK: and %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @and32(i32 %x, i32 %y) { + %a = and i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: or32: +; CHECK: or %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @or32(i32 %x, i32 %y) { + %a = or i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: xor32: +; CHECK: xor %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @xor32(i32 %x, i32 %y) { + %a = xor i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: shl32: +; CHECK: sh %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @shl32(i32 %x, i32 %y) { + %a = shl i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: shr32: +; CHECK: sub %r0, %r{{[0-9]+}}, %r{{[0-9]+}} +; CHECK: sh %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @shr32(i32 %x, i32 %y) { + %a = lshr i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: sar32 +; CHECK: sub %r0, %r{{[0-9]+}}, %r{{[0-9]+}} +; CHECK: sha %r{{[0-9]+}}, %r{{[0-9]+}}, %rv +define i32 @sar32(i32 %x, i32 %y) { + %a = ashr i32 %x, %y + ret i32 %a +} + +; CHECK-LABEL: clz32: +; CHECK: leadz %r{{[0-9]+}}, %rv +define i32 @clz32(i32 %x) { + %a = call i32 @llvm.ctlz.i32(i32 %x, i1 false) + ret i32 %a +} + +; CHECK-LABEL: clz32_zero_undef: +; CHECK-NOT: sub.f +; CHECK: leadz %r{{[0-9]+}}, %rv +define i32 @clz32_zero_undef(i32 %x) { + %a = call i32 @llvm.ctlz.i32(i32 %x, i1 true) + ret i32 %a +} + +; CHECK-LABEL: ctz32: +; CHECK: trailz %r{{[0-9]+}}, %rv +define i32 @ctz32(i32 %x) { + %a = call i32 @llvm.cttz.i32(i32 %x, i1 false) + ret i32 %a +} + +; CHECK-LABEL: ctz32_zero_undef: +; CHECK-NOT: sub.f +; CHECK: trailz %r{{[0-9]+}}, %rv +define i32 @ctz32_zero_undef(i32 %x) { + %a = call i32 @llvm.cttz.i32(i32 %x, i1 true) + ret i32 %a +} + +; CHECK-LABEL: popcnt32: +; CHECK: popc %r{{[0-9]+}}, %rv +define i32 @popcnt32(i32 %x) { + %a = call i32 @llvm.ctpop.i32(i32 %x) + ret i32 %a +} Index: test/CodeGen/Lanai/mem_alu_combiner.ll =================================================================== --- test/CodeGen/Lanai/mem_alu_combiner.ll +++ test/CodeGen/Lanai/mem_alu_combiner.ll @@ -0,0 +1,40 @@ +; RUN: llc < %s -march=lanai | FileCheck %s +; RUN: llc < %s -march=lanai -disable-lanai-mem-alu-combiner | \ +; RUN: FileCheck %s -check-prefix=CHECK-DIS + +; CHECK-LABEL: sum, +; CHECK: ++], +; CHECK-DIS-LABEL: sum, +; CHECK-DIS-NOT: ++], + +define i32 @sum(i32* inreg nocapture readonly %data, i32 inreg %n) #0 { +entry: + %cmp6 = icmp sgt i32 %n, 0 + br i1 %cmp6, label %for.body.preheader, label %for.cond.cleanup + +for.body.preheader: ; preds = %entry + br label %for.body + +for.cond.cleanup.loopexit: ; preds = %for.body + %add.lcssa = phi i32 [ %add, %for.body ] + br label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond.cleanup.loopexit, %entry + %sum_.0.lcssa = phi i32 [ 0, %entry ], [ %add.lcssa, %for.cond.cleanup.loopexit ] + ret i32 %sum_.0.lcssa + +for.body: ; preds = %for.body.preheader, %for.body + %i.08 = phi i32 [ %inc, %for.body ], [ 0, %for.body.preheader ] + %sum_.07 = phi i32 [ %add, %for.body ], [ 0, %for.body.preheader ] + %arrayidx = getelementptr inbounds i32, i32* %data, i32 %i.08 + %0 = load i32, i32* %arrayidx, align 4, !tbaa !0 + %add = add nsw i32 %0, %sum_.07 + %inc = add nuw nsw i32 %i.08, 1 + %exitcond = icmp eq i32 %inc, %n + br i1 %exitcond, label %for.cond.cleanup.loopexit, label %for.body +} + +!0 = !{!1, !1, i64 0} +!1 = !{!"int", !2, i64 0} +!2 = !{!"omnipotent char", !3, i64 0} +!3 = !{!"Simple C/C++ TBAA"} Index: test/CodeGen/Lanai/multiply.ll =================================================================== --- test/CodeGen/Lanai/multiply.ll +++ test/CodeGen/Lanai/multiply.ll @@ -0,0 +1,60 @@ +; RUN: llc -march=lanai < %s | FileCheck %s + +; Test the in place lowering of mul i32. + +define i32 @f6(i32 inreg %a) #0 { +entry: + %mul = mul nsw i32 %a, 6 + ret i32 %mul +} +; CHECK: sh %r6, 0x1, %r{{[0-9]+}} +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv + +define i32 @f7(i32 inreg %a) #0 { +entry: + %mul = mul nsw i32 %a, 7 + ret i32 %mul +} +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r6, %rv + +define i32 @f8(i32 inreg %a) #0 { +entry: + %mul = shl nsw i32 %a, 3 + ret i32 %mul +} +; CHECK: sh %r6, 0x3, %rv + +define i32 @fm6(i32 inreg %a) #0 { +entry: + %mul = mul nsw i32 %a, -6 + ret i32 %mul +} +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sh %r6, 0x1, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv + +define i32 @fm7(i32 inreg %a) #0 { +entry: + %mul = mul nsw i32 %a, -7 + ret i32 %mul +} +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sub %r6, %r{{[0-9]+}}, %rv + +define i32 @fm8(i32 inreg %a) #0 { +entry: + %mul = mul nsw i32 %a, -8 + ret i32 %mul +} +; CHECK: sh %r6, 0x3, %r{{[0-9]+}} +; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv + +define i32 @h1(i32 inreg %a) #0 { +entry: + %mul = mul i32 %a, -1431655765 + ret i32 %mul +} +; CHECK: h1 +; CHECK: mulsi3 Index: test/CodeGen/Lanai/select.ll =================================================================== --- test/CodeGen/Lanai/select.ll +++ test/CodeGen/Lanai/select.ll @@ -0,0 +1,41 @@ +; RUN: llc < %s | FileCheck %s + +; Test that Lanai select instruction is selected from LLVM select instruction. + +target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "lanai" + +; CHECK-LABEL: select_i32_bool: +; CHECK: sub.f %r6, 0x0, %r0 +; CHECK: sel.ne %r7, %r18, %rv +define i32 @select_i32_bool(i1 inreg %a, i32 inreg %b, i32 inreg %c) { + %cond = select i1 %a, i32 %b, i32 %c + ret i32 %cond +} + +; CHECK-LABEL: select_i32_eq: +; CHECK: sub.f %r6, 0x0, %r0 +; CHECK: sel.eq %r7, %r18, %rv +define i32 @select_i32_eq(i32 inreg %a, i32 inreg %b, i32 inreg %c) { + %cmp = icmp eq i32 %a, 0 + %cond = select i1 %cmp, i32 %b, i32 %c + ret i32 %cond +} + +; CHECK-LABEL: select_i32_ne: +; CHECK: sub.f %r6, 0x0, %r0 +; CHECK: sel.ne %r7, %r18, %rv +define i32 @select_i32_ne(i32 inreg %a, i32 inreg %b, i32 inreg %c) { + %cmp = icmp ne i32 %a, 0 + %cond = select i1 %cmp, i32 %b, i32 %c + ret i32 %cond +} + +; CHECK-LABEL: select_i32_lt: +; CHECK: sub.f %r6, %r7, %r0 +; CHECK: sel.lt %r6, %r7, %rv +define i32 @select_i32_lt(i32 inreg %x, i32 inreg %y) #0 { + %1 = icmp slt i32 %x, %y + %2 = select i1 %1, i32 %x, i32 %y + ret i32 %2 +} Index: test/CodeGen/Lanai/set_and_hi.ll =================================================================== --- test/CodeGen/Lanai/set_and_hi.ll +++ test/CodeGen/Lanai/set_and_hi.ll @@ -0,0 +1,15 @@ +; RUN: llc < %s | FileCheck %s + +; Test matching of and_hi. + +target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "lanai" + +@x = common global i32 0, align 4 + +; CHECK-LABEL: setandhi: +; CHECK: mov 0xfffffe4a, %r{{[0-9]+}} +define void @setandhi() #0 { + store volatile i32 -438, i32* @x, align 4 + ret void +} Index: test/CodeGen/Lanai/stack-frame.ll =================================================================== --- test/CodeGen/Lanai/stack-frame.ll +++ test/CodeGen/Lanai/stack-frame.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=lanai < %s -o - | FileCheck %s + +define void @f1() { + %c = alloca i8, align 1 + ret void +} +; CHECK-LABEL: f1: +; CHECK: sub %sp, 0x10 + +define i32 @f2() { + ret i32 1 +} +; CHECK-LABEL: f2: +; CHECK: sub %sp, 0x8 Index: test/DebugInfo/Lanai/processes-relocations.ll =================================================================== --- test/DebugInfo/Lanai/processes-relocations.ll +++ test/DebugInfo/Lanai/processes-relocations.ll @@ -1,9 +1,5 @@ -; RUN: llvm-dwarfdump %p/Inputs/lanai-processes-relocations.elf 2>&1 | FileCheck %s - -; FIXME: Use llc with this file as input instead of binary file. -; NOTE: this test is currently not using llc, but using a binary input as the -; rest of the backend is not yet in tree. Once the Lanai backend is in tree, -; the binary file will be removed and this test will use llc. +; RUN: llc -filetype=obj -O0 < %s -mtriple lanai-unknown-unknown | \ +; RUN: llvm-dwarfdump - 2>&1 | FileCheck %s ; CHECK-NOT: failed to compute relocation @@ -15,5 +11,5 @@ !1 = !{!"empty.c", !"/a"} !2 = !{} !3 = !{i32 2, !"Dwarf Version", i32 4} -!4 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 2, !"Debug Info Version", i32 1} !5 = !{!"clang version 3.6.0 "} Index: test/MC/Disassembler/Lanai/v11.txt =================================================================== --- test/MC/Disassembler/Lanai/v11.txt +++ test/MC/Disassembler/Lanai/v11.txt @@ -0,0 +1,762 @@ +# RUN: llvm-mc -disassemble -triple lanai %s | FileCheck %s + +0x0a 0xc4 0x00 0x00 +# CHECK: add %r17, 0x0, %r21 +0x0a 0xc4 0x12 0x34 +# CHECK: add %r17, 0x1234, %r21 +0x0a 0xc5 0x12 0x34 +# CHECK: add %r17, 0x12340000, %r21 +0x0a 0xc6 0x00 0x00 +# CHECK: add.f %r17, 0x0, %r21 +0x0a 0xc6 0x12 0x34 +# CHECK: add.f %r17, 0x1234, %r21 +0x0a 0xc7 0x12 0x34 +# CHECK: add.f %r17, 0x12340000, %r21 +0xca 0xc4 0x90 0x00 +# CHECK: add %r17, %r18, %r21 +0xca 0xc6 0x90 0x00 +# CHECK: add.f %r17, %r18, %r21 +0xca 0xc4 0x91 0x00 +# CHECK: addc %r17, %r18, %r21 +0xca 0xc6 0x91 0x00 +# CHECK: addc.f %r17, %r18, %r21 +0x1a 0xc4 0x00 0x00 +# CHECK: addc %r17, 0x0, %r21 +0x1a 0xc4 0x12 0x34 +# CHECK: addc %r17, 0x1234, %r21 +0x1a 0xc5 0x12 0x34 +# CHECK: addc %r17, 0x12340000, %r21 +0x1a 0xc6 0x00 0x00 +# CHECK: addc.f %r17, 0x0, %r21 +0x1a 0xc6 0x12 0x34 +# CHECK: addc.f %r17, 0x1234, %r21 +0x1a 0xc7 0x12 0x34 +# CHECK: addc.f %r17, 0x12340000, %r21 +0x4a 0xc4 0x12 0x34 +# CHECK: and %r17, 0xffff1234, %r21 +0x4a 0xc5 0x12 0x34 +# CHECK: and %r17, 0x1234ffff, %r21 +0x4a 0xc6 0x12 0x34 +# CHECK: and.f %r17, 0xffff1234, %r21 +0x4a 0xc7 0x12 0x34 +# CHECK: and.f %r17, 0x1234ffff, %r21 +0xca 0xc4 0x94 0x00 +# CHECK: and %r17, %r18, %r21 +0xca 0xc6 0x94 0x00 +# CHECK: and.f %r17, %r18, %r21 +0xe0 0x12 0x34 0x54 +# CHECK: bt 0x123454 +0xe0 0x12 0x34 0x55 +# CHECK: bf 0x123454 +0xe2 0x12 0x34 0x54 +# CHECK: bugt 0x123454 +0xe2 0x12 0x34 0x55 +# CHECK: bule 0x123454 +0xe4 0x12 0x34 0x54 +# CHECK: bult 0x123454 +0xe4 0x12 0x34 0x55 +# CHECK: buge 0x123454 +0xe6 0x12 0x34 0x54 +# CHECK: bne 0x123454 +0xe6 0x12 0x34 0x55 +# CHECK: beq 0x123454 +0xe8 0x12 0x34 0x54 +# CHECK: bvc 0x123454 +0xe8 0x12 0x34 0x55 +# CHECK: bvs 0x123454 +0xea 0x12 0x34 0x54 +# CHECK: bpl 0x123454 +0xea 0x12 0x34 0x55 +# CHECK: bmi 0x123454 +0xec 0x12 0x34 0x54 +# CHECK: bge 0x123454 +0xec 0x12 0x34 0x55 +# CHECK: blt 0x123454 +0xee 0x12 0x34 0x54 +# CHECK: bgt 0x123454 +0xc1 0x00 0x9d 0x00 +# CHECK: bt %r19 +0xe1 0x00 0x56 0x7a +# CHECK: bt.r 0x5678 +0xe1 0x00 0x56 0x7b +# CHECK: bf.r 0x5678 +0xe3 0x00 0x56 0x7a +# CHECK: bugt.r 0x5678 +0xe3 0x00 0x56 0x7b +# CHECK: bule.r 0x5678 +0xe5 0x00 0x56 0x7a +# CHECK: bult.r 0x5678 +0xe5 0x00 0x56 0x7b +# CHECK: buge.r 0x5678 +0xe7 0x00 0x56 0x7a +# CHECK: bne.r 0x5678 +0xe7 0x00 0x56 0x7b +# CHECK: beq.r 0x5678 +0xe9 0x00 0x56 0x7a +# CHECK: bvc.r 0x5678 +0xe9 0x00 0x56 0x7b +# CHECK: bvs.r 0x5678 +0xeb 0x00 0x56 0x7a +# CHECK: bpl.r 0x5678 +0xeb 0x00 0x56 0x7b +# CHECK: bmi.r 0x5678 +0xed 0x00 0x56 0x7a +# CHECK: bge.r 0x5678 +0xed 0x00 0x56 0x7b +# CHECK: blt.r 0x5678 +0xef 0x00 0x56 0x7a +# CHECK: bgt.r 0x5678 +0x8a 0xc6 0x80 0x00 +# CHECK: ld -32768[%r17], %r21 +0x8a 0xc6 0xfc 0x00 +# CHECK: ld -1024[%r17], %r21 +0x8a 0xc4 0x00 0x00 +# CHECK: ld 0[%r17], %r21 +0x8a 0xc6 0x04 0x00 +# CHECK: ld 1024[%r17], %r21 +0x8a 0xc6 0x7f 0xff +# CHECK: ld 32767[%r17], %r21 +0xaa 0xc6 0x90 0x02 +# CHECK: ld [%r17 add %r18], %r21 +0xaa 0xc6 0x90 0x03 +# CHECK: uld [%r17 add %r18], %r21 +0xfa 0xc7 0x0a 0x00 +# CHECK: ld.h -512[%r17], %r21 +0xfa 0xc7 0x0b 0xf3 +# CHECK: ld.h -13[%r17], %r21 +0xfa 0xc7 0x08 0x12 +# CHECK: ld.h 18[%r17], %r21 +0xfa 0xc7 0x09 0xff +# CHECK: ld.h 511[%r17], %r21 +0xfa 0xc7 0x4a 0x00 +# CHECK: ld.b -512[%r17], %r21 +0xfa 0xc7 0x4b 0xf3 +# CHECK: ld.b -13[%r17], %r21 +0xfa 0xc7 0x48 0x12 +# CHECK: ld.b 18[%r17], %r21 +0xfa 0xc7 0x49 0xff +# CHECK: ld.b 511[%r17], %r21 +0xfa 0xc7 0x1a 0x00 +# CHECK: uld.h -512[%r17], %r21 +0xfa 0xc7 0x1b 0xf3 +# CHECK: uld.h -13[%r17], %r21 +0xfa 0xc7 0x18 0x12 +# CHECK: uld.h 18[%r17], %r21 +0xfa 0xc7 0x19 0xff +# CHECK: uld.h 511[%r17], %r21 +0xfa 0xc7 0x5a 0x00 +# CHECK: uld.b -512[%r17], %r21 +0xfa 0xc7 0x5b 0xf3 +# CHECK: uld.b -13[%r17], %r21 +0xfa 0xc7 0x58 0x12 +# CHECK: uld.b 18[%r17], %r21 +0xfa 0xc7 0x59 0xff +# CHECK: uld.b 511[%r17], %r21 +0x8a 0xc7 0x80 0x00 +# CHECK: ld -32768[*%r17], %r21 +0x8a 0xc7 0xfc 0x00 +# CHECK: ld -1024[*%r17], %r21 +0x8a 0xc7 0x04 0x00 +# CHECK: ld 1024[*%r17], %r21 +0x8a 0xc7 0x7f 0xff +# CHECK: ld 32767[*%r17], %r21 +0x8a 0xc7 0xff 0xfc +# CHECK: ld [--%r17], %r21 +0x8a 0xc7 0x00 0x04 +# CHECK: ld [++%r17], %r21 +0xfa 0xc7 0x0f 0xfe +# CHECK: ld.h [--%r17], %r21 +0xfa 0xc7 0x0c 0x02 +# CHECK: ld.h [++%r17], %r21 +0xfa 0xc7 0x1f 0xfe +# CHECK: uld.h [--%r17], %r21 +0xfa 0xc7 0x1c 0x02 +# CHECK: uld.h [++%r17], %r21 +0xfa 0xc7 0x4f 0xff +# CHECK: ld.b [--%r17], %r21 +0xfa 0xc7 0x4c 0x01 +# CHECK: ld.b [++%r17], %r21 +0xfa 0xc7 0x5f 0xff +# CHECK: uld.b [--%r17], %r21 +0xfa 0xc7 0x5c 0x01 +# CHECK: uld.b [++%r17], %r21 +0xaa 0xc7 0x90 0x02 +# CHECK: ld [*%r17 add %r18], %r21 +0xfa 0xc7 0x0e 0x00 +# CHECK: ld.h -512[*%r17], %r21 +0xfa 0xc7 0x0f 0xf3 +# CHECK: ld.h -13[*%r17], %r21 +0xfa 0xc7 0x0c 0x12 +# CHECK: ld.h 18[*%r17], %r21 +0xfa 0xc7 0x0d 0xff +# CHECK: ld.h 511[*%r17], %r21 +0xfa 0xc7 0x4e 0x00 +# CHECK: ld.b -512[*%r17], %r21 +0xfa 0xc7 0x4f 0xf3 +# CHECK: ld.b -13[*%r17], %r21 +0xfa 0xc7 0x4c 0x12 +# CHECK: ld.b 18[*%r17], %r21 +0xfa 0xc7 0x4d 0xff +# CHECK: ld.b 511[*%r17], %r21 +0xfa 0xc7 0x1e 0x00 +# CHECK: uld.h -512[*%r17], %r21 +0xfa 0xc7 0x1f 0xf3 +# CHECK: uld.h -13[*%r17], %r21 +0xfa 0xc7 0x1c 0x12 +# CHECK: uld.h 18[*%r17], %r21 +0xfa 0xc7 0x1d 0xff +# CHECK: uld.h 511[*%r17], %r21 +0xfa 0xc7 0x5e 0x00 +# CHECK: uld.b -512[*%r17], %r21 +0xfa 0xc7 0x5f 0xf3 +# CHECK: uld.b -13[*%r17], %r21 +0xfa 0xc7 0x5c 0x12 +# CHECK: uld.b 18[*%r17], %r21 +0xfa 0xc7 0x5d 0xff +# CHECK: uld.b 511[*%r17], %r21 +0x8a 0xc5 0x80 0x00 +# CHECK: ld -32768[%r17*], %r21 +0x8a 0xc5 0xfc 0x00 +# CHECK: ld -1024[%r17*], %r21 +0x8a 0xc5 0x04 0x00 +# CHECK: ld 1024[%r17*], %r21 +0x8a 0xc5 0x7f 0xff +# CHECK: ld 32767[%r17*], %r21 +0x8a 0xc5 0xff 0xfc +# CHECK: ld [%r17--], %r21 +0x8a 0xc5 0x00 0x04 +# CHECK: ld [%r17++], %r21 +0xfa 0xc7 0x07 0xfe +# CHECK: ld.h [%r17--], %r21 +0xfa 0xc7 0x04 0x02 +# CHECK: ld.h [%r17++], %r21 +0xfa 0xc7 0x17 0xfe +# CHECK: uld.h [%r17--], %r21 +0xfa 0xc7 0x14 0x02 +# CHECK: uld.h [%r17++], %r21 +0xfa 0xc7 0x47 0xff +# CHECK: ld.b [%r17--], %r21 +0xfa 0xc7 0x44 0x01 +# CHECK: ld.b [%r17++], %r21 +0xfa 0xc7 0x57 0xff +# CHECK: uld.b [%r17--], %r21 +0xfa 0xc7 0x54 0x01 +# CHECK: uld.b [%r17++], %r21 +0xaa 0xc5 0x90 0x02 +# CHECK: ld [%r17* add %r18], %r21 +0xfa 0xc7 0x06 0x00 +# CHECK: ld.h -512[%r17*], %r21 +0xfa 0xc7 0x07 0xf3 +# CHECK: ld.h -13[%r17*], %r21 +0xfa 0xc7 0x04 0x12 +# CHECK: ld.h 18[%r17*], %r21 +0xfa 0xc7 0x05 0xff +# CHECK: ld.h 511[%r17*], %r21 +0xfa 0xc7 0x46 0x00 +# CHECK: ld.b -512[%r17*], %r21 +0xfa 0xc7 0x47 0xf3 +# CHECK: ld.b -13[%r17*], %r21 +0xfa 0xc7 0x44 0x12 +# CHECK: ld.b 18[%r17*], %r21 +0xfa 0xc7 0x45 0xff +# CHECK: ld.b 511[%r17*], %r21 +0xfa 0xc7 0x16 0x00 +# CHECK: uld.h -512[%r17*], %r21 +0xfa 0xc7 0x17 0xf3 +# CHECK: uld.h -13[%r17*], %r21 +0xfa 0xc7 0x14 0x12 +# CHECK: uld.h 18[%r17*], %r21 +0xfa 0xc7 0x15 0xff +# CHECK: uld.h 511[%r17*], %r21 +0xfa 0xc7 0x56 0x00 +# CHECK: uld.b -512[%r17*], %r21 +0xfa 0xc7 0x57 0xf3 +# CHECK: uld.b -13[%r17*], %r21 +0xfa 0xc7 0x54 0x12 +# CHECK: uld.b 18[%r17*], %r21 +0xfa 0xc7 0x55 0xff +# CHECK: uld.b 511[%r17*], %r21 +0xaa 0xc6 0x90 0x02 +# CHECK: ld [%r17 add %r18], %r21 +0xaa 0xc6 0x91 0x02 +# CHECK: ld [%r17 addc %r18], %r21 +0xaa 0xc6 0x92 0x02 +# CHECK: ld [%r17 sub %r18], %r21 +0xaa 0xc6 0x93 0x02 +# CHECK: ld [%r17 subb %r18], %r21 +0xaa 0xc6 0x94 0x02 +# CHECK: ld [%r17 and %r18], %r21 +0xaa 0xc6 0x95 0x02 +# CHECK: ld [%r17 or %r18], %r21 +0xaa 0xc6 0x96 0x02 +# CHECK: ld [%r17 xor %r18], %r21 +0xaa 0xc6 0x97 0x82 +# CHECK: ld [%r17 sh %r18], %r21 +0xaa 0xc6 0x97 0xc2 +# CHECK: ld [%r17 sha %r18], %r21 +0xaa 0xc7 0x90 0x02 +# CHECK: ld [*%r17 add %r18], %r21 +0xaa 0xc7 0x91 0x02 +# CHECK: ld [*%r17 addc %r18], %r21 +0xaa 0xc7 0x92 0x02 +# CHECK: ld [*%r17 sub %r18], %r21 +0xaa 0xc7 0x93 0x02 +# CHECK: ld [*%r17 subb %r18], %r21 +0xaa 0xc7 0x94 0x02 +# CHECK: ld [*%r17 and %r18], %r21 +0xaa 0xc7 0x95 0x02 +# CHECK: ld [*%r17 or %r18], %r21 +0xaa 0xc7 0x96 0x02 +# CHECK: ld [*%r17 xor %r18], %r21 +0xaa 0xc7 0x97 0x82 +# CHECK: ld [*%r17 sh %r18], %r21 +0xaa 0xc7 0x97 0xc2 +# CHECK: ld [*%r17 sha %r18], %r21 +0xaa 0xc5 0x90 0x02 +# CHECK: ld [%r17* add %r18], %r21 +0xaa 0xc5 0x91 0x02 +# CHECK: ld [%r17* addc %r18], %r21 +0xaa 0xc5 0x92 0x02 +# CHECK: ld [%r17* sub %r18], %r21 +0xaa 0xc5 0x93 0x02 +# CHECK: ld [%r17* subb %r18], %r21 +0xaa 0xc5 0x94 0x02 +# CHECK: ld [%r17* and %r18], %r21 +0xaa 0xc5 0x95 0x02 +# CHECK: ld [%r17* or %r18], %r21 +0xaa 0xc5 0x96 0x02 +# CHECK: ld [%r17* xor %r18], %r21 +0xaa 0xc5 0x97 0x82 +# CHECK: ld [%r17* sh %r18], %r21 +0xaa 0xc5 0x97 0xc2 +# CHECK: ld [%r17* sha %r18], %r21 +0xfa 0x84 0x23 0x44 +# CHECK: ld [0x12344], %r21 +0xda 0xc4 0x00 0x02 +# CHECK: leadz %r17, %r21 +0x08 0x80 0x00 0x00 +# CHECK: mov 0x0, %r17 +0x08 0x80 0x12 0x34 +# CHECK: mov 0x1234, %r17 +0x08 0x81 0x12 0x34 +# CHECK: mov 0x12340000, %r17 +0x08 0x81 0xaa 0xaa +# CHECK: mov 0xaaaa0000, %r17 +0xc8 0xc8 0x00 0x00 +# CHECK: mov %r18, %r17 +0xf8 0x86 0x23 0x44 +# CHECK: mov 0x12344, %r17 +0x48 0x84 0x12 0x34 +# CHECK: mov 0xffff1234, %r17 +0x48 0x85 0x12 0x34 +# CHECK: mov 0x1234ffff, %r17 +0x00 0x00 0x00 0x01 +# CHECK: nop +0x5a 0xc4 0x00 0x00 +# CHECK: or %r17, 0x0, %r21 +0x5a 0xc4 0x12 0x34 +# CHECK: or %r17, 0x1234, %r21 +0x5a 0xc5 0x12 0x34 +# CHECK: or %r17, 0x12340000, %r21 +0x5a 0xc6 0x00 0x00 +# CHECK: or.f %r17, 0x0, %r21 +0x5a 0xc6 0x12 0x34 +# CHECK: or.f %r17, 0x1234, %r21 +0x5a 0xc7 0x12 0x34 +# CHECK: or.f %r17, 0x12340000, %r21 +0xca 0xc4 0x95 0x00 +# CHECK: or %r17, %r18, %r21 +0xca 0xc6 0x95 0x00 +# CHECK: or.f %r17, %r18, %r21 +0xda 0xc4 0x00 0x01 +# CHECK: popc %r17, %r21 +0xe0 0x54 0x00 0x02 +# CHECK: st %r21 +0xe2 0x54 0x00 0x02 +# CHECK: sugt %r21 +0xe2 0x54 0x00 0x03 +# CHECK: sule %r21 +0xe4 0x54 0x00 0x02 +# CHECK: sult %r21 +0xe4 0x54 0x00 0x03 +# CHECK: suge %r21 +0xe6 0x54 0x00 0x02 +# CHECK: sne %r21 +0xe6 0x54 0x00 0x03 +# CHECK: seq %r21 +0xe8 0x54 0x00 0x02 +# CHECK: svc %r21 +0xe8 0x54 0x00 0x03 +# CHECK: svs %r21 +0xea 0x54 0x00 0x02 +# CHECK: spl %r21 +0xea 0x54 0x00 0x03 +# CHECK: smi %r21 +0xec 0x54 0x00 0x02 +# CHECK: sge %r21 +0xec 0x54 0x00 0x03 +# CHECK: slt %r21 +0xee 0x54 0x00 0x02 +# CHECK: sgt %r21 +0x7a 0xc4 0xff 0xe1 +# CHECK: sh %r17, -0x1f, %r21 +0x7a 0xc4 0xff 0xfb +# CHECK: sh %r17, -0x5, %r21 +0x7a 0xc4 0x00 0x02 +# CHECK: sh %r17, 0x2, %r21 +0x7a 0xc4 0x00 0x1f +# CHECK: sh %r17, 0x1f, %r21 +0x7a 0xc6 0xff 0xe1 +# CHECK: sh.f %r17, -0x1f, %r21 +0x7a 0xc6 0xff 0xfb +# CHECK: sh.f %r17, -0x5, %r21 +0x7a 0xc6 0x00 0x02 +# CHECK: sh.f %r17, 0x2, %r21 +0x7a 0xc6 0x00 0x1f +# CHECK: sh.f %r17, 0x1f, %r21 +0xca 0xc4 0x97 0x80 +# CHECK: sh %r17, %r18, %r21 +0xca 0xc6 0x97 0x80 +# CHECK: sh.f %r17, %r18, %r21 +0x7a 0xc5 0xff 0xe1 +# CHECK: sha %r17, -0x1f, %r21 +0x7a 0xc5 0xff 0xfb +# CHECK: sha %r17, -0x5, %r21 +0x7a 0xc5 0x00 0x02 +# CHECK: sha %r17, 0x2, %r21 +0x7a 0xc5 0x00 0x1f +# CHECK: sha %r17, 0x1f, %r21 +0x7a 0xc7 0xff 0xe1 +# CHECK: sha.f %r17, -0x1f, %r21 +0x7a 0xc7 0xff 0xfb +# CHECK: sha.f %r17, -0x5, %r21 +0x7a 0xc7 0x00 0x02 +# CHECK: sha.f %r17, 0x2, %r21 +0x7a 0xc7 0x00 0x1f +# CHECK: sha.f %r17, 0x1f, %r21 +0xca 0xc4 0x97 0xc0 +# CHECK: sha %r17, %r18, %r21 +0xca 0xc6 0x97 0xc0 +# CHECK: sha.f %r17, %r18, %r21 +0x98 0xce 0x80 0x00 +# CHECK: st %r17, -32768[%r19] +0x98 0xce 0xfc 0x00 +# CHECK: st %r17, -1024[%r19] +0x98 0xcc 0x00 0x00 +# CHECK: st %r17, 0[%r19] +0x98 0xce 0x04 0x00 +# CHECK: st %r17, 1024[%r19] +0x98 0xce 0x7f 0xff +# CHECK: st %r17, 32767[%r19] +0xf8 0xcf 0x2a 0x00 +# CHECK: st.h %r17, -512[%r19] +0xf8 0xcf 0x2b 0xf3 +# CHECK: st.h %r17, -13[%r19] +0xf8 0xcf 0x28 0x12 +# CHECK: st.h %r17, 18[%r19] +0xf8 0xcf 0x29 0xff +# CHECK: st.h %r17, 511[%r19] +0xf8 0xcf 0x6a 0x00 +# CHECK: st.b %r17, -512[%r19] +0xf8 0xcf 0x6b 0xf3 +# CHECK: st.b %r17, -13[%r19] +0xf8 0xcf 0x68 0x12 +# CHECK: st.b %r17, 18[%r19] +0xf8 0xcf 0x69 0xff +# CHECK: st.b %r17, 511[%r19] +0xb8 0xce 0x90 0x02 +# CHECK: st %r17, [%r19 add %r18] +0xb8 0xce 0x90 0x00 +# CHECK: st.h %r17, [%r19 add %r18] +0xb8 0xce 0x90 0x04 +# CHECK: st.b %r17, [%r19 add %r18] +0x98 0xcf 0x80 0x00 +# CHECK: st %r17, -32768[*%r19] +0x98 0xcf 0xfc 0x00 +# CHECK: st %r17, -1024[*%r19] +0x98 0xcf 0x04 0x00 +# CHECK: st %r17, 1024[*%r19] +0x98 0xcf 0x7f 0xff +# CHECK: st %r17, 32767[*%r19] +0xf8 0xcf 0x2e 0x00 +# CHECK: st.h %r17, -512[*%r19] +0xf8 0xcf 0x2f 0xf3 +# CHECK: st.h %r17, -13[*%r19] +0xf8 0xcf 0x2c 0x12 +# CHECK: st.h %r17, 18[*%r19] +0xf8 0xcf 0x2d 0xff +# CHECK: st.h %r17, 511[*%r19] +0xf8 0xcf 0x6e 0x00 +# CHECK: st.b %r17, -512[*%r19] +0xf8 0xcf 0x6f 0xf3 +# CHECK: st.b %r17, -13[*%r19] +0xf8 0xcf 0x6c 0x12 +# CHECK: st.b %r17, 18[*%r19] +0xf8 0xcf 0x6d 0xff +# CHECK: st.b %r17, 511[*%r19] +0x98 0xcf 0xff 0xfc +# CHECK: st %r17, [--%r19] +0x98 0xcf 0x00 0x04 +# CHECK: st %r17, [++%r19] +0xf8 0xcf 0x2f 0xfe +# CHECK: st.h %r17, [--%r19] +0xf8 0xcf 0x2c 0x02 +# CHECK: st.h %r17, [++%r19] +0xf8 0xcf 0x6f 0xff +# CHECK: st.b %r17, [--%r19] +0xf8 0xcf 0x6c 0x01 +# CHECK: st.b %r17, [++%r19] +0xb8 0xcf 0x90 0x02 +# CHECK: st %r17, [*%r19 add %r18] +0xb8 0xcf 0x90 0x00 +# CHECK: st.h %r17, [*%r19 add %r18] +0xb8 0xcf 0x90 0x04 +# CHECK: st.b %r17, [*%r19 add %r18] +0x98 0xcd 0x80 0x00 +# CHECK: st %r17, -32768[%r19*] +0x98 0xcd 0xfc 0x00 +# CHECK: st %r17, -1024[%r19*] +0x98 0xcd 0x04 0x00 +# CHECK: st %r17, 1024[%r19*] +0x98 0xcd 0x7f 0xff +# CHECK: st %r17, 32767[%r19*] +0xf8 0xcf 0x26 0x00 +# CHECK: st.h %r17, -512[%r19*] +0xf8 0xcf 0x27 0xf3 +# CHECK: st.h %r17, -13[%r19*] +0xf8 0xcf 0x24 0x12 +# CHECK: st.h %r17, 18[%r19*] +0xf8 0xcf 0x25 0xff +# CHECK: st.h %r17, 511[%r19*] +0xf8 0xcf 0x66 0x00 +# CHECK: st.b %r17, -512[%r19*] +0xf8 0xcf 0x67 0xf3 +# CHECK: st.b %r17, -13[%r19*] +0xf8 0xcf 0x64 0x12 +# CHECK: st.b %r17, 18[%r19*] +0xf8 0xcf 0x65 0xff +# CHECK: st.b %r17, 511[%r19*] +0x98 0xcd 0xff 0xfc +# CHECK: st %r17, [%r19--] +0x98 0xcd 0x00 0x04 +# CHECK: st %r17, [%r19++] +0xf8 0xcf 0x27 0xfe +# CHECK: st.h %r17, [%r19--] +0xf8 0xcf 0x24 0x02 +# CHECK: st.h %r17, [%r19++] +0xf8 0xcf 0x67 0xff +# CHECK: st.b %r17, [%r19--] +0xf8 0xcf 0x64 0x01 +# CHECK: st.b %r17, [%r19++] +0xb8 0xcd 0x90 0x02 +# CHECK: st %r17, [%r19* add %r18] +0xb8 0xcd 0x90 0x00 +# CHECK: st.h %r17, [%r19* add %r18] +0xb8 0xcd 0x90 0x04 +# CHECK: st.b %r17, [%r19* add %r18] +0xba 0xc6 0x90 0x02 +# CHECK: st %r21, [%r17 add %r18] +0xba 0xc6 0x91 0x02 +# CHECK: st %r21, [%r17 addc %r18] +0xba 0xc6 0x92 0x02 +# CHECK: st %r21, [%r17 sub %r18] +0xba 0xc6 0x93 0x02 +# CHECK: st %r21, [%r17 subb %r18] +0xba 0xc6 0x94 0x02 +# CHECK: st %r21, [%r17 and %r18] +0xba 0xc6 0x95 0x02 +# CHECK: st %r21, [%r17 or %r18] +0xba 0xc6 0x96 0x02 +# CHECK: st %r21, [%r17 xor %r18] +0xba 0xc6 0x97 0x82 +# CHECK: st %r21, [%r17 sh %r18] +0xba 0xc6 0x97 0xc2 +# CHECK: st %r21, [%r17 sha %r18] +0xba 0xc6 0x90 0x00 +# CHECK: st.h %r21, [%r17 add %r18] +0xba 0xc6 0x91 0x00 +# CHECK: st.h %r21, [%r17 addc %r18] +0xba 0xc6 0x92 0x00 +# CHECK: st.h %r21, [%r17 sub %r18] +0xba 0xc6 0x93 0x00 +# CHECK: st.h %r21, [%r17 subb %r18] +0xba 0xc6 0x94 0x00 +# CHECK: st.h %r21, [%r17 and %r18] +0xba 0xc6 0x95 0x00 +# CHECK: st.h %r21, [%r17 or %r18] +0xba 0xc6 0x96 0x00 +# CHECK: st.h %r21, [%r17 xor %r18] +0xba 0xc6 0x97 0x80 +# CHECK: st.h %r21, [%r17 sh %r18] +0xba 0xc6 0x97 0xc0 +# CHECK: st.h %r21, [%r17 sha %r18] +0xba 0xc6 0x90 0x04 +# CHECK: st.b %r21, [%r17 add %r18] +0xba 0xc6 0x91 0x04 +# CHECK: st.b %r21, [%r17 addc %r18] +0xba 0xc6 0x92 0x04 +# CHECK: st.b %r21, [%r17 sub %r18] +0xba 0xc6 0x93 0x04 +# CHECK: st.b %r21, [%r17 subb %r18] +0xba 0xc6 0x94 0x04 +# CHECK: st.b %r21, [%r17 and %r18] +0xba 0xc6 0x95 0x04 +# CHECK: st.b %r21, [%r17 or %r18] +0xba 0xc6 0x96 0x04 +# CHECK: st.b %r21, [%r17 xor %r18] +0xba 0xc6 0x97 0x84 +# CHECK: st.b %r21, [%r17 sh %r18] +0xba 0xc6 0x97 0xc4 +# CHECK: st.b %r21, [%r17 sha %r18] +0xba 0xc7 0x90 0x02 +# CHECK: st %r21, [*%r17 add %r18] +0xba 0xc7 0x91 0x02 +# CHECK: st %r21, [*%r17 addc %r18] +0xba 0xc7 0x92 0x02 +# CHECK: st %r21, [*%r17 sub %r18] +0xba 0xc7 0x93 0x02 +# CHECK: st %r21, [*%r17 subb %r18] +0xba 0xc7 0x94 0x02 +# CHECK: st %r21, [*%r17 and %r18] +0xba 0xc7 0x95 0x02 +# CHECK: st %r21, [*%r17 or %r18] +0xba 0xc7 0x96 0x02 +# CHECK: st %r21, [*%r17 xor %r18] +0xba 0xc7 0x97 0xc2 +# CHECK: st %r21, [*%r17 sha %r18] +0xba 0xc7 0x90 0x00 +# CHECK: st.h %r21, [*%r17 add %r18] +0xba 0xc7 0x91 0x00 +# CHECK: st.h %r21, [*%r17 addc %r18] +0xba 0xc7 0x92 0x00 +# CHECK: st.h %r21, [*%r17 sub %r18] +0xba 0xc7 0x93 0x00 +# CHECK: st.h %r21, [*%r17 subb %r18] +0xba 0xc7 0x94 0x00 +# CHECK: st.h %r21, [*%r17 and %r18] +0xba 0xc7 0x95 0x00 +# CHECK: st.h %r21, [*%r17 or %r18] +0xba 0xc7 0x96 0x00 +# CHECK: st.h %r21, [*%r17 xor %r18] +0xba 0xc7 0x97 0xc0 +# CHECK: st.h %r21, [*%r17 sha %r18] +0xba 0xc7 0x90 0x04 +# CHECK: st.b %r21, [*%r17 add %r18] +0xba 0xc7 0x91 0x04 +# CHECK: st.b %r21, [*%r17 addc %r18] +0xba 0xc7 0x92 0x04 +# CHECK: st.b %r21, [*%r17 sub %r18] +0xba 0xc7 0x93 0x04 +# CHECK: st.b %r21, [*%r17 subb %r18] +0xba 0xc7 0x94 0x04 +# CHECK: st.b %r21, [*%r17 and %r18] +0xba 0xc7 0x95 0x04 +# CHECK: st.b %r21, [*%r17 or %r18] +0xba 0xc7 0x96 0x04 +# CHECK: st.b %r21, [*%r17 xor %r18] +0xba 0xc7 0x97 0xc4 +# CHECK: st.b %r21, [*%r17 sha %r18] +0xba 0xc5 0x90 0x02 +# CHECK: st %r21, [%r17* add %r18] +0xba 0xc5 0x91 0x02 +# CHECK: st %r21, [%r17* addc %r18] +0xba 0xc5 0x92 0x02 +# CHECK: st %r21, [%r17* sub %r18] +0xba 0xc5 0x93 0x02 +# CHECK: st %r21, [%r17* subb %r18] +0xba 0xc5 0x94 0x02 +# CHECK: st %r21, [%r17* and %r18] +0xba 0xc5 0x95 0x02 +# CHECK: st %r21, [%r17* or %r18] +0xba 0xc5 0x96 0x02 +# CHECK: st %r21, [%r17* xor %r18] +0xba 0xc5 0x97 0x82 +# CHECK: st %r21, [%r17* sh %r18] +0xba 0xc5 0x97 0xc2 +# CHECK: st %r21, [%r17* sha %r18] +0xba 0xc5 0x90 0x00 +# CHECK: st.h %r21, [%r17* add %r18] +0xba 0xc5 0x91 0x00 +# CHECK: st.h %r21, [%r17* addc %r18] +0xba 0xc5 0x92 0x00 +# CHECK: st.h %r21, [%r17* sub %r18] +0xba 0xc5 0x93 0x00 +# CHECK: st.h %r21, [%r17* subb %r18] +0xba 0xc5 0x94 0x00 +# CHECK: st.h %r21, [%r17* and %r18] +0xba 0xc5 0x95 0x00 +# CHECK: st.h %r21, [%r17* or %r18] +0xba 0xc5 0x96 0x00 +# CHECK: st.h %r21, [%r17* xor %r18] +0xba 0xc5 0x97 0x80 +# CHECK: st.h %r21, [%r17* sh %r18] +0xba 0xc5 0x97 0xc0 +# CHECK: st.h %r21, [%r17* sha %r18] +0xba 0xc5 0x90 0x04 +# CHECK: st.b %r21, [%r17* add %r18] +0xba 0xc5 0x91 0x04 +# CHECK: st.b %r21, [%r17* addc %r18] +0xba 0xc5 0x92 0x04 +# CHECK: st.b %r21, [%r17* sub %r18] +0xba 0xc5 0x93 0x04 +# CHECK: st.b %r21, [%r17* subb %r18] +0xba 0xc5 0x94 0x04 +# CHECK: st.b %r21, [%r17* and %r18] +0xba 0xc5 0x95 0x04 +# CHECK: st.b %r21, [%r17* or %r18] +0xba 0xc5 0x96 0x04 +# CHECK: st.b %r21, [%r17* xor %r18] +0xba 0xc5 0x97 0x84 +# CHECK: st.b %r21, [%r17* sh %r18] +0xba 0xc5 0x97 0xc4 +# CHECK: st.b %r21, [%r17* sha %r18] +0xfa 0x85 0x23 0x44 +# CHECK: st %r21, [0x12344] +0x2a 0xc4 0x00 0x00 +# CHECK: sub %r17, 0x0, %r21 +0x2a 0xc4 0x12 0x34 +# CHECK: sub %r17, 0x1234, %r21 +0x2a 0xc5 0x12 0x34 +# CHECK: sub %r17, 0x12340000, %r21 +0x2a 0xc6 0x00 0x00 +# CHECK: sub.f %r17, 0x0, %r21 +0x2a 0xc6 0x12 0x34 +# CHECK: sub.f %r17, 0x1234, %r21 +0x2a 0xc7 0x12 0x34 +# CHECK: sub.f %r17, 0x12340000, %r21 +0xca 0xc4 0x92 0x00 +# CHECK: sub %r17, %r18, %r21 +0xca 0xc6 0x92 0x00 +# CHECK: sub.f %r17, %r18, %r21 +0x3a 0xc4 0x00 0x00 +# CHECK: subb %r17, 0x0, %r21 +0x3a 0xc4 0x12 0x34 +# CHECK: subb %r17, 0x1234, %r21 +0x3a 0xc5 0x12 0x34 +# CHECK: subb %r17, 0x12340000, %r21 +0x3a 0xc6 0x00 0x00 +# CHECK: subb.f %r17, 0x0, %r21 +0x3a 0xc6 0x12 0x34 +# CHECK: subb.f %r17, 0x1234, %r21 +0x3a 0xc7 0x12 0x34 +# CHECK: subb.f %r17, 0x12340000, %r21 +0xca 0xc4 0x93 0x00 +# CHECK: subb %r17, %r18, %r21 +0xca 0xc6 0x93 0x00 +# CHECK: subb.f %r17, %r18, %r21 +0x6a 0xc4 0x00 0x00 +# CHECK: xor %r17, 0x0, %r21 +0x6a 0xc4 0x12 0x34 +# CHECK: xor %r17, 0x1234, %r21 +0x6a 0xc5 0x12 0x34 +# CHECK: xor %r17, 0x12340000, %r21 +0x6a 0xc6 0x00 0x00 +# CHECK: xor.f %r17, 0x0, %r21 +0x6a 0xc6 0x12 0x34 +# CHECK: xor.f %r17, 0x1234, %r21 +0x6a 0xc7 0x12 0x34 +# CHECK: xor.f %r17, 0x12340000, %r21 +0xca 0xc4 0x96 0x00 +# CHECK: xor %r17, %r18, %r21 +0xca 0xc6 0x96 0x00 +# CHECK: xor.f %r17, %r18, %r21 Index: test/MC/Lanai/v11.s =================================================================== --- test/MC/Lanai/v11.s +++ test/MC/Lanai/v11.s @@ -0,0 +1,830 @@ +! RUN: llvm-mc -arch=lanai -show-encoding %s | FileCheck %s + +add %r17, 0, %r21 +! CHECK: 0x0a,0xc4,0x00,0x00 +add %r17, 0x00001234, %r21 +! CHECK: 0x0a,0xc4,0x12,0x34 +add %r17, 0x12340000, %r21 +! CHECK: 0x0a,0xc5,0x12,0x34 +add.f %r17, 0, %r21 +! CHECK: 0x0a,0xc6,0x00,0x00 +add.f %r17, 0x00001234, %r21 +! CHECK: 0x0a,0xc6,0x12,0x34 +add.f %r17, 0x12340000, %r21 +! CHECK: 0x0a,0xc7,0x12,0x34 +add %r17, %r18, %r21 +! CHECK: 0xca,0xc4,0x90,0x00 +add.f %r17, %r18, %r21 +! CHECK: 0xca,0xc6,0x90,0x00 +addc %r17, %r18, %r21 +! CHECK: 0xca,0xc4,0x91,0x00 +addc.f %r17, %r18, %r21 +! CHECK: 0xca,0xc6,0x91,0x00 +addc %r17, 0, %r21 +! CHECK: 0x1a,0xc4,0x00,0x00 +addc %r17, 0x00001234, %r21 +! CHECK: 0x1a,0xc4,0x12,0x34 +addc %r17, 0x12340000, %r21 +! CHECK: 0x1a,0xc5,0x12,0x34 +addc.f %r17, 0, %r21 +! CHECK: 0x1a,0xc6,0x00,0x00 +addc.f %r17, 0x00001234, %r21 +! CHECK: 0x1a,0xc6,0x12,0x34 +addc.f %r17, 0x12340000, %r21 +! CHECK: 0x1a,0xc7,0x12,0x34 +and %r17, 0xffff1234, %r21 +! CHECK: 0x4a,0xc4,0x12,0x34 +and %r17, 0x1234ffff, %r21 +! CHECK: 0x4a,0xc5,0x12,0x34 +and.f %r17, 0xffff1234, %r21 +! CHECK: 0x4a,0xc6,0x12,0x34 +and.f %r17, 0x1234ffff, %r21 +! CHECK: 0x4a,0xc7,0x12,0x34 +and %r17, %r18, %r21 +! CHECK: 0xca,0xc4,0x94,0x00 +and.f %r17, %r18, %r21 +! CHECK: 0xca,0xc6,0x94,0x00 +bt 0x123454 +! CHECK: 0xe0,0x12,0x34,0x54 +bf 0x123454 +! CHECK: 0xe0,0x12,0x34,0x55 +bhi 0x123454 +! CHECK: 0xe2,0x12,0x34,0x54 +bugt 0x123454 +! CHECK: 0xe2,0x12,0x34,0x54 +bls 0x123454 +! CHECK: 0xe2,0x12,0x34,0x55 +bule 0x123454 +! CHECK: 0xe2,0x12,0x34,0x55 +bcc 0x123454 +! CHECK: 0xe4,0x12,0x34,0x54 +bult 0x123454 +! CHECK: 0xe4,0x12,0x34,0x54 +bcs 0x123454 +! CHECK: 0xe4,0x12,0x34,0x55 +buge 0x123454 +! CHECK: 0xe4,0x12,0x34,0x55 +bne 0x123454 +! CHECK: 0xe6,0x12,0x34,0x54 +beq 0x123454 +! CHECK: 0xe6,0x12,0x34,0x55 +bvc 0x123454 +! CHECK: 0xe8,0x12,0x34,0x54 +bvs 0x123454 +! CHECK: 0xe8,0x12,0x34,0x55 +bpl 0x123454 +! CHECK: 0xea,0x12,0x34,0x54 +bmi 0x123454 +! CHECK: 0xea,0x12,0x34,0x55 +bge 0x123454 +! CHECK: 0xec,0x12,0x34,0x54 +blt 0x123454 +! CHECK: 0xec,0x12,0x34,0x55 +bgt 0x123454 +! CHECK: 0xee,0x12,0x34,0x54 +bt %r19 +! CHECK: 0xc1,0x00,0x9d,0x00 +bt.r 0x5678 +! CHECK: 0xe1,0x00,0x56,0x7a +bf.r 0x5678 +! CHECK: 0xe1,0x00,0x56,0x7b +bhi.r 0x5678 +! CHECK: 0xe3,0x00,0x56,0x7a +bugt.r 0x5678 +! CHECK: 0xe3,0x00,0x56,0x7a +bls.r 0x5678 +! CHECK: 0xe3,0x00,0x56,0x7b +bule.r 0x5678 +! CHECK: 0xe3,0x00,0x56,0x7b +bcc.r 0x5678 +! CHECK: 0xe5,0x00,0x56,0x7a +bult.r 0x5678 +! CHECK: 0xe5,0x00,0x56,0x7a +bcs.r 0x5678 +! CHECK: 0xe5,0x00,0x56,0x7b +buge.r 0x5678 +! CHECK: 0xe5,0x00,0x56,0x7b +bne.r 0x5678 +! CHECK: 0xe7,0x00,0x56,0x7a +beq.r 0x5678 +! CHECK: 0xe7,0x00,0x56,0x7b +bvc.r 0x5678 +! CHECK: 0xe9,0x00,0x56,0x7a +bvs.r 0x5678 +! CHECK: 0xe9,0x00,0x56,0x7b +bpl.r 0x5678 +! CHECK: 0xeb,0x00,0x56,0x7a +bmi.r 0x5678 +! CHECK: 0xeb,0x00,0x56,0x7b +bge.r 0x5678 +! CHECK: 0xed,0x00,0x56,0x7a +blt.r 0x5678 +! CHECK: 0xed,0x00,0x56,0x7b +bgt.r 0x5678 +! CHECK: 0xef,0x00,0x56,0x7a +ld -32768[%r17], %r21 +! CHECK: 0x8a,0xc6,0x80,0x00 +ld -1024[%r17], %r21 +! CHECK: 0x8a,0xc6,0xfc,0x00 +ld 0[%r17], %r21 +! CHECK: 0x8a,0xc4,0x00,0x00 +ld 1024[%r17], %r21 +! CHECK: 0x8a,0xc6,0x04,0x00 +ld 32767[%r17], %r21 +! CHECK: 0x8a,0xc6,0x7f,0xff +uld -32768[%r17], %r21 +! CHECK: 0x8a,0xc6,0x80,0x00 +uld -1024[%r17], %r21 +! CHECK: 0x8a,0xc6,0xfc,0x00 +uld 0[%r17], %r21 +! CHECK: 0x8a,0xc4,0x00,0x00 +uld 1024[%r17], %r21 +! CHECK: 0x8a,0xc6,0x04,0x00 +uld 32767[%r17], %r21 +! CHECK: 0x8a,0xc6,0x7f,0xff +ld %r18[%r17], %r21 +! CHECK: 0xaa,0xc6,0x90,0x02 +uld %r18[%r17], %r21 +! CHECK: 0xaa,0xc6,0x90,0x03 +ld.h -512[%r17], %r21 +! CHECK: 0xfa,0xc7,0x0a,0x00 +ld.h -13[%r17], %r21 +! CHECK: 0xfa,0xc7,0x0b,0xf3 +ld.h 18[%r17], %r21 +! CHECK: 0xfa,0xc7,0x08,0x12 +ld.h 511[%r17], %r21 +! CHECK: 0xfa,0xc7,0x09,0xff +ld.b -512[%r17], %r21 +! CHECK: 0xfa,0xc7,0x4a,0x00 +ld.b -13[%r17], %r21 +! CHECK: 0xfa,0xc7,0x4b,0xf3 +ld.b 18[%r17], %r21 +! CHECK: 0xfa,0xc7,0x48,0x12 +ld.b 511[%r17], %r21 +! CHECK: 0xfa,0xc7,0x49,0xff +uld.h -512[%r17], %r21 +! CHECK: 0xfa,0xc7,0x1a,0x00 +uld.h -13[%r17], %r21 +! CHECK: 0xfa,0xc7,0x1b,0xf3 +uld.h 18[%r17], %r21 +! CHECK: 0xfa,0xc7,0x18,0x12 +uld.h 511[%r17], %r21 +! CHECK: 0xfa,0xc7,0x19,0xff +uld.b -512[%r17], %r21 +! CHECK: 0xfa,0xc7,0x5a,0x00 +uld.b -13[%r17], %r21 +! CHECK: 0xfa,0xc7,0x5b,0xf3 +uld.b 18[%r17], %r21 +! CHECK: 0xfa,0xc7,0x58,0x12 +uld.b 511[%r17], %r21 +! CHECK: 0xfa,0xc7,0x59,0xff +ld -32768[*%r17], %r21 +! CHECK: 0x8a,0xc7,0x80,0x00 +ld -1024[*%r17], %r21 +! CHECK: 0x8a,0xc7,0xfc,0x00 +ld 0[*%r17], %r21 +! CHECK: 0x8a,0xc4,0x00,0x00 +ld 1024[*%r17], %r21 +! CHECK: 0x8a,0xc7,0x04,0x00 +ld 32767[*%r17], %r21 +! CHECK: 0x8a,0xc7,0x7f,0xff +uld -32768[*%r17], %r21 +! CHECK: 0x8a,0xc7,0x80,0x00 +uld -1024[*%r17], %r21 +! CHECK: 0x8a,0xc7,0xfc,0x00 +uld 0[*%r17], %r21 +! CHECK: 0x8a,0xc4,0x00,0x00 +uld 1024[*%r17], %r21 +! CHECK: 0x8a,0xc7,0x04,0x00 +uld 32767[*%r17], %r21 +! CHECK: 0x8a,0xc7,0x7f,0xff +ld [--%r17], %r21 +! CHECK: 0x8a,0xc7,0xff,0xfc +ld [++%r17], %r21 +! CHECK: 0x8a,0xc7,0x00,0x04 +ld.h [--%r17], %r21 +! CHECK: 0xfa,0xc7,0x0f,0xfe +ld.h [++%r17], %r21 +! CHECK: 0xfa,0xc7,0x0c,0x02 +uld.h [--%r17], %r21 +! CHECK: 0xfa,0xc7,0x1f,0xfe +uld.h [++%r17], %r21 +! CHECK: 0xfa,0xc7,0x1c,0x02 +ld.b [--%r17], %r21 +! CHECK: 0xfa,0xc7,0x4f,0xff +ld.b [++%r17], %r21 +! CHECK: 0xfa,0xc7,0x4c,0x01 +uld.b [--%r17], %r21 +! CHECK: 0xfa,0xc7,0x5f,0xff +uld.b [++%r17], %r21 +! CHECK: 0xfa,0xc7,0x5c,0x01 +ld %r18[*%r17], %r21 +! CHECK: 0xaa,0xc7,0x90,0x02 +uld %r18[*%r17], %r21 +! CHECK: 0xaa,0xc7,0x90,0x03 +ld.h -512[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x0e,0x00 +ld.h -13[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x0f,0xf3 +ld.h 18[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x0c,0x12 +ld.h 511[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x0d,0xff +ld.b -512[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x4e,0x00 +ld.b -13[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x4f,0xf3 +ld.b 18[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x4c,0x12 +ld.b 511[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x4d,0xff +uld.h -512[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x1e,0x00 +uld.h -13[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x1f,0xf3 +uld.h 18[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x1c,0x12 +uld.h 511[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x1d,0xff +uld.b -512[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x5e,0x00 +uld.b -13[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x5f,0xf3 +uld.b 18[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x5c,0x12 +uld.b 511[*%r17], %r21 +! CHECK: 0xfa,0xc7,0x5d,0xff +ld -32768[%r17*], %r21 +! CHECK: 0x8a,0xc5,0x80,0x00 +ld -1024[%r17*], %r21 +! CHECK: 0x8a,0xc5,0xfc,0x00 +ld 0[%r17*], %r21 +! CHECK: 0x8a,0xc4,0x00,0x00 +ld 1024[%r17*], %r21 +! CHECK: 0x8a,0xc5,0x04,0x00 +ld 32767[%r17*], %r21 +! CHECK: 0x8a,0xc5,0x7f,0xff +uld -32768[%r17*], %r21 +! CHECK: 0x8a,0xc5,0x80,0x00 +uld -1024[%r17*], %r21 +! CHECK: 0x8a,0xc5,0xfc,0x00 +uld 0[%r17*], %r21 +! CHECK: 0x8a,0xc4,0x00,0x00 +uld 1024[%r17*], %r21 +! CHECK: 0x8a,0xc5,0x04,0x00 +uld 32767[%r17*], %r21 +! CHECK: 0x8a,0xc5,0x7f,0xff +ld [%r17--], %r21 +! CHECK: 0x8a,0xc5,0xff,0xfc +ld [%r17++], %r21 +! CHECK: 0x8a,0xc5,0x00,0x04 +ld.h [%r17--], %r21 +! CHECK: 0xfa,0xc7,0x07,0xfe +ld.h [%r17++], %r21 +! CHECK: 0xfa,0xc7,0x04,0x02 +uld.h [%r17--], %r21 +! CHECK: 0xfa,0xc7,0x17,0xfe +uld.h [%r17++], %r21 +! CHECK: 0xfa,0xc7,0x14,0x02 +ld.b [%r17--], %r21 +! CHECK: 0xfa,0xc7,0x47,0xff +ld.b [%r17++], %r21 +! CHECK: 0xfa,0xc7,0x44,0x01 +uld.b [%r17--], %r21 +! CHECK: 0xfa,0xc7,0x57,0xff +uld.b [%r17++], %r21 +! CHECK: 0xfa,0xc7,0x54,0x01 +ld %r18[%r17*], %r21 +! CHECK: 0xaa,0xc5,0x90,0x02 +uld %r18[%r17*], %r21 +! CHECK: 0xaa,0xc5,0x90,0x03 +ld.h -512[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x06,0x00 +ld.h -13[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x07,0xf3 +ld.h 18[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x04,0x12 +ld.h 511[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x05,0xff +ld.b -512[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x46,0x00 +ld.b -13[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x47,0xf3 +ld.b 18[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x44,0x12 +ld.b 511[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x45,0xff +uld.h -512[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x16,0x00 +uld.h -13[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x17,0xf3 +uld.h 18[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x14,0x12 +uld.h 511[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x15,0xff +uld.b -512[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x56,0x00 +uld.b -13[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x57,0xf3 +uld.b 18[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x54,0x12 +uld.b 511[%r17*], %r21 +! CHECK: 0xfa,0xc7,0x55,0xff +ld [%r17 add %r18], %r21 +! CHECK: 0xaa,0xc6,0x90,0x02 +ld [%r17 addc %r18], %r21 +! CHECK: 0xaa,0xc6,0x91,0x02 +ld [%r17 sub %r18], %r21 +! CHECK: 0xaa,0xc6,0x92,0x02 +ld [%r17 subb %r18], %r21 +! CHECK: 0xaa,0xc6,0x93,0x02 +ld [%r17 and %r18], %r21 +! CHECK: 0xaa,0xc6,0x94,0x02 +ld [%r17 or %r18], %r21 +! CHECK: 0xaa,0xc6,0x95,0x02 +ld [%r17 xor %r18], %r21 +! CHECK: 0xaa,0xc6,0x96,0x02 +ld [%r17 sh %r18], %r21 +! CHECK: 0xaa,0xc6,0x97,0x82 +ld [%r17 sha %r18], %r21 +! CHECK: 0xaa,0xc6,0x97,0xc2 +ld [*%r17 add %r18], %r21 +! CHECK: 0xaa,0xc7,0x90,0x02 +ld [*%r17 addc %r18], %r21 +! CHECK: 0xaa,0xc7,0x91,0x02 +ld [*%r17 sub %r18], %r21 +! CHECK: 0xaa,0xc7,0x92,0x02 +ld [*%r17 subb %r18], %r21 +! CHECK: 0xaa,0xc7,0x93,0x02 +ld [*%r17 and %r18], %r21 +! CHECK: 0xaa,0xc7,0x94,0x02 +ld [*%r17 or %r18], %r21 +! CHECK: 0xaa,0xc7,0x95,0x02 +ld [*%r17 xor %r18], %r21 +! CHECK: 0xaa,0xc7,0x96,0x02 +ld [*%r17 sh %r18], %r21 +! CHECK: 0xaa,0xc7,0x97,0x82 +ld [*%r17 sha %r18], %r21 +! CHECK: 0xaa,0xc7,0x97,0xc2 +ld [%r17* add %r18], %r21 +! CHECK: 0xaa,0xc5,0x90,0x02 +ld [%r17* addc %r18], %r21 +! CHECK: 0xaa,0xc5,0x91,0x02 +ld [%r17* sub %r18], %r21 +! CHECK: 0xaa,0xc5,0x92,0x02 +ld [%r17* subb %r18], %r21 +! CHECK: 0xaa,0xc5,0x93,0x02 +ld [%r17* and %r18], %r21 +! CHECK: 0xaa,0xc5,0x94,0x02 +ld [%r17* or %r18], %r21 +! CHECK: 0xaa,0xc5,0x95,0x02 +ld [%r17* xor %r18], %r21 +! CHECK: 0xaa,0xc5,0x96,0x02 +ld [%r17* sh %r18], %r21 +! CHECK: 0xaa,0xc5,0x97,0x82 +ld [%r17* sha %r18], %r21 +! CHECK: 0xaa,0xc5,0x97,0xc2 +ld [0x12344], %r21 +! CHECK: 0xfa,0x84,0x23,0x44 +leadz %r17, %r21 +! CHECK: 0xda,0xc4,0x00,0x02 +mov 0, %r17 +! CHECK: 0x08,0x80,0x00,0x00 +mov 0x00001234, %r17 +! CHECK: 0x08,0x80,0x12,0x34 +mov 0x12340000, %r17 +! CHECK: 0x08,0x81,0x12,0x34 +mov 0xaaaa0000, %r17 +! CHECK: 0x08,0x81,0xaa,0xaa +mov %r18, %r17 +! CHECK: 0xc8,0xc8,0x00,0x00 +mov 0x12344, %r17 +! CHECK: 0xf8,0x86,0x23,0x44 +mov 0xffff1234, %r17 +! CHECK: 0x48,0x84,0x12,0x34 +mov 0x1234ffff, %r17 +! CHECK: 0x48,0x85,0x12,0x34 +nop +! CHECK: 0x00,0x00,0x00,0x01 +or %r17, 0, %r21 +! CHECK: 0x5a,0xc4,0x00,0x00 +or %r17, 0x00001234, %r21 +! CHECK: 0x5a,0xc4,0x12,0x34 +or %r17, 0x12340000, %r21 +! CHECK: 0x5a,0xc5,0x12,0x34 +or.f %r17, 0, %r21 +! CHECK: 0x5a,0xc6,0x00,0x00 +or.f %r17, 0x00001234, %r21 +! CHECK: 0x5a,0xc6,0x12,0x34 +or.f %r17, 0x12340000, %r21 +! CHECK: 0x5a,0xc7,0x12,0x34 +or %r17, %r18, %r21 +! CHECK: 0xca,0xc4,0x95,0x00 +or.f %r17, %r18, %r21 +! CHECK: 0xca,0xc6,0x95,0x00 +popc %r17, %r21 +! CHECK: 0xda,0xc4,0x00,0x01 +st %r21 +! CHECK: 0xe0,0x54,0x00,0x02 +shi %r21 +! CHECK: 0xe2,0x54,0x00,0x02 +sugt %r21 +! CHECK: 0xe2,0x54,0x00,0x02 +sls %r21 +! CHECK: 0xe2,0x54,0x00,0x03 +sule %r21 +! CHECK: 0xe2,0x54,0x00,0x03 +scc %r21 +! CHECK: 0xe4,0x54,0x00,0x02 +sult %r21 +! CHECK: 0xe4,0x54,0x00,0x02 +scs %r21 +! CHECK: 0xe4,0x54,0x00,0x03 +suge %r21 +! CHECK: 0xe4,0x54,0x00,0x03 +sne %r21 +! CHECK: 0xe6,0x54,0x00,0x02 +seq %r21 +! CHECK: 0xe6,0x54,0x00,0x03 +svc %r21 +! CHECK: 0xe8,0x54,0x00,0x02 +svs %r21 +! CHECK: 0xe8,0x54,0x00,0x03 +spl %r21 +! CHECK: 0xea,0x54,0x00,0x02 +smi %r21 +! CHECK: 0xea,0x54,0x00,0x03 +sge %r21 +! CHECK: 0xec,0x54,0x00,0x02 +slt %r21 +! CHECK: 0xec,0x54,0x00,0x03 +sgt %r21 +! CHECK: 0xee,0x54,0x00,0x02 +sh %r17, -31, %r21 +! CHECK: 0x7a,0xc4,0xff,0xe1 +sh %r17, -5, %r21 +! CHECK: 0x7a,0xc4,0xff,0xfb +sh %r17, 2, %r21 +! CHECK: 0x7a,0xc4,0x00,0x02 +sh %r17, 31, %r21 +! CHECK: 0x7a,0xc4,0x00,0x1f +sh.f %r17, -31, %r21 +! CHECK: 0x7a,0xc6,0xff,0xe1 +sh.f %r17, -5, %r21 +! CHECK: 0x7a,0xc6,0xff,0xfb +sh.f %r17, 2, %r21 +! CHECK: 0x7a,0xc6,0x00,0x02 +sh.f %r17, 31, %r21 +! CHECK: 0x7a,0xc6,0x00,0x1f +sh %r17, %r18, %r21 +! CHECK: 0xca,0xc4,0x97,0x80 +sh.f %r17, %r18, %r21 +! CHECK: 0xca,0xc6,0x97,0x80 +sha %r17, -31, %r21 +! CHECK: 0x7a,0xc5,0xff,0xe1 +sha %r17, -5, %r21 +! CHECK: 0x7a,0xc5,0xff,0xfb +sha %r17, 2, %r21 +! CHECK: 0x7a,0xc5,0x00,0x02 +sha %r17, 31, %r21 +! CHECK: 0x7a,0xc5,0x00,0x1f +sha.f %r17, -31, %r21 +! CHECK: 0x7a,0xc7,0xff,0xe1 +sha.f %r17, -5, %r21 +! CHECK: 0x7a,0xc7,0xff,0xfb +sha.f %r17, 2, %r21 +! CHECK: 0x7a,0xc7,0x00,0x02 +sha.f %r17, 31, %r21 +! CHECK: 0x7a,0xc7,0x00,0x1f +sha %r17, %r18, %r21 +! CHECK: 0xca,0xc4,0x97,0xc0 +sha.f %r17, %r18, %r21 +! CHECK: 0xca,0xc6,0x97,0xc0 +st %r17, -32768[%r19] +! CHECK: 0x98,0xce,0x80,0x00 +st %r17, -1024[%r19] +! CHECK: 0x98,0xce,0xfc,0x00 +st %r17, 0[%r19] +! CHECK: 0x98,0xcc,0x00,0x00 +st %r17, 1024[%r19] +! CHECK: 0x98,0xce,0x04,0x00 +st %r17, 32767[%r19] +! CHECK: 0x98,0xce,0x7f,0xff +st.h %r17, -512[%r19] +! CHECK: 0xf8,0xcf,0x2a,0x00 +st.h %r17, -13[%r19] +! CHECK: 0xf8,0xcf,0x2b,0xf3 +st.h %r17, 18[%r19] +! CHECK: 0xf8,0xcf,0x28,0x12 +st.h %r17, 511[%r19] +! CHECK: 0xf8,0xcf,0x29,0xff +st.b %r17, -512[%r19] +! CHECK: 0xf8,0xcf,0x6a,0x00 +st.b %r17, -13[%r19] +! CHECK: 0xf8,0xcf,0x6b,0xf3 +st.b %r17, 18[%r19] +! CHECK: 0xf8,0xcf,0x68,0x12 +st.b %r17, 511[%r19] +! CHECK: 0xf8,0xcf,0x69,0xff +st %r17, %r18[%r19] +! CHECK: 0xb8,0xce,0x90,0x02 +st.h %r17, %r18[%r19] +! CHECK: 0xb8,0xce,0x90,0x00 +st.b %r17, %r18[%r19] +! CHECK: 0xb8,0xce,0x90,0x04 +st %r17, -32768[*%r19] +! CHECK: 0x98,0xcf,0x80,0x00 +st %r17, -1024[*%r19] +! CHECK: 0x98,0xcf,0xfc,0x00 +st %r17, 0[*%r19] +! CHECK: 0x98,0xcc,0x00,0x00 +st %r17, 1024[*%r19] +! CHECK: 0x98,0xcf,0x04,0x00 +st %r17, 32767[*%r19] +! CHECK: 0x98,0xcf,0x7f,0xff +st.h %r17, -512[*%r19] +! CHECK: 0xf8,0xcf,0x2e,0x00 +st.h %r17, -13[*%r19] +! CHECK: 0xf8,0xcf,0x2f,0xf3 +st.h %r17, 18[*%r19] +! CHECK: 0xf8,0xcf,0x2c,0x12 +st.h %r17, 511[*%r19] +! CHECK: 0xf8,0xcf,0x2d,0xff +st.b %r17, -512[*%r19] +! CHECK: 0xf8,0xcf,0x6e,0x00 +st.b %r17, -13[*%r19] +! CHECK: 0xf8,0xcf,0x6f,0xf3 +st.b %r17, 18[*%r19] +! CHECK: 0xf8,0xcf,0x6c,0x12 +st.b %r17, 511[*%r19] +! CHECK: 0xf8,0xcf,0x6d,0xff +st %r17, [--%r19] +! CHECK: 0x98,0xcf,0xff,0xfc +st %r17, [++%r19] +! CHECK: 0x98,0xcf,0x00,0x04 +st.h %r17, [--%r19] +! CHECK: 0xf8,0xcf,0x2f,0xfe +st.h %r17, [++%r19] +! CHECK: 0xf8,0xcf,0x2c,0x02 +st.b %r17, [--%r19] +! CHECK: 0xf8,0xcf,0x6f,0xff +st.b %r17, [++%r19] +! CHECK: 0xf8,0xcf,0x6c,0x01 +st %r17, %r18[*%r19] +! CHECK: 0xb8,0xcf,0x90,0x02 +st.h %r17, %r18[*%r19] +! CHECK: 0xb8,0xcf,0x90,0x00 +st.b %r17, %r18[*%r19] +! CHECK: 0xb8,0xcf,0x90,0x04 +st %r17, -32768[%r19*] +! CHECK: 0x98,0xcd,0x80,0x00 +st %r17, -1024[%r19*] +! CHECK: 0x98,0xcd,0xfc,0x00 +st %r17, 0[%r19*] +! CHECK: 0x98,0xcc,0x00,0x00 +st %r17, 1024[%r19*] +! CHECK: 0x98,0xcd,0x04,0x00 +st %r17, 32767[%r19*] +! CHECK: 0x98,0xcd,0x7f,0xff +st.h %r17, -512[%r19*] +! CHECK: 0xf8,0xcf,0x26,0x00 +st.h %r17, -13[%r19*] +! CHECK: 0xf8,0xcf,0x27,0xf3 +st.h %r17, 18[%r19*] +! CHECK: 0xf8,0xcf,0x24,0x12 +st.h %r17, 511[%r19*] +! CHECK: 0xf8,0xcf,0x25,0xff +st.b %r17, -512[%r19*] +! CHECK: 0xf8,0xcf,0x66,0x00 +st.b %r17, -13[%r19*] +! CHECK: 0xf8,0xcf,0x67,0xf3 +st.b %r17, 18[%r19*] +! CHECK: 0xf8,0xcf,0x64,0x12 +st.b %r17, 511[%r19*] +! CHECK: 0xf8,0xcf,0x65,0xff +st %r17, [%r19--] +! CHECK: 0x98,0xcd,0xff,0xfc +st %r17, [%r19++] +! CHECK: 0x98,0xcd,0x00,0x04 +st.h %r17, [%r19--] +! CHECK: 0xf8,0xcf,0x27,0xfe +st.h %r17, [%r19++] +! CHECK: 0xf8,0xcf,0x24,0x02 +st.b %r17, [%r19--] +! CHECK: 0xf8,0xcf,0x67,0xff +st.b %r17, [%r19++] +! CHECK: 0xf8,0xcf,0x64,0x01 +st %r17, %r18[%r19*] +! CHECK: 0xb8,0xcd,0x90,0x02 +st.h %r17, %r18[%r19*] +! CHECK: 0xb8,0xcd,0x90,0x00 +st.b %r17, %r18[%r19*] +! CHECK: 0xb8,0xcd,0x90,0x04 +st %r21, [%r17 add %r18] +! CHECK: 0xba,0xc6,0x90,0x02 +st %r21, [%r17 addc %r18] +! CHECK: 0xba,0xc6,0x91,0x02 +st %r21, [%r17 sub %r18] +! CHECK: 0xba,0xc6,0x92,0x02 +st %r21, [%r17 subb %r18] +! CHECK: 0xba,0xc6,0x93,0x02 +st %r21, [%r17 and %r18] +! CHECK: 0xba,0xc6,0x94,0x02 +st %r21, [%r17 or %r18] +! CHECK: 0xba,0xc6,0x95,0x02 +st %r21, [%r17 xor %r18] +! CHECK: 0xba,0xc6,0x96,0x02 +st %r21, [%r17 sh %r18] +! CHECK: 0xba,0xc6,0x97,0x82 +st %r21, [%r17 sha %r18] +! CHECK: 0xba,0xc6,0x97,0xc2 +st.h %r21, [%r17 add %r18] +! CHECK: 0xba,0xc6,0x90,0x00 +st.h %r21, [%r17 addc %r18] +! CHECK: 0xba,0xc6,0x91,0x00 +st.h %r21, [%r17 sub %r18] +! CHECK: 0xba,0xc6,0x92,0x00 +st.h %r21, [%r17 subb %r18] +! CHECK: 0xba,0xc6,0x93,0x00 +st.h %r21, [%r17 and %r18] +! CHECK: 0xba,0xc6,0x94,0x00 +st.h %r21, [%r17 or %r18] +! CHECK: 0xba,0xc6,0x95,0x00 +st.h %r21, [%r17 xor %r18] +! CHECK: 0xba,0xc6,0x96,0x00 +st.h %r21, [%r17 sh %r18] +! CHECK: 0xba,0xc6,0x97,0x80 +st.h %r21, [%r17 sha %r18] +! CHECK: 0xba,0xc6,0x97,0xc0 +st.b %r21, [%r17 add %r18] +! CHECK: 0xba,0xc6,0x90,0x04 +st.b %r21, [%r17 addc %r18] +! CHECK: 0xba,0xc6,0x91,0x04 +st.b %r21, [%r17 sub %r18] +! CHECK: 0xba,0xc6,0x92,0x04 +st.b %r21, [%r17 subb %r18] +! CHECK: 0xba,0xc6,0x93,0x04 +st.b %r21, [%r17 and %r18] +! CHECK: 0xba,0xc6,0x94,0x04 +st.b %r21, [%r17 or %r18] +! CHECK: 0xba,0xc6,0x95,0x04 +st.b %r21, [%r17 xor %r18] +! CHECK: 0xba,0xc6,0x96,0x04 +st.b %r21, [%r17 sh %r18] +! CHECK: 0xba,0xc6,0x97,0x84 +st.b %r21, [%r17 sha %r18] +! CHECK: 0xba,0xc6,0x97,0xc4 +st %r21, [*%r17 add %r18] +! CHECK: 0xba,0xc7,0x90,0x02 +st %r21, [*%r17 addc %r18] +! CHECK: 0xba,0xc7,0x91,0x02 +st %r21, [*%r17 sub %r18] +! CHECK: 0xba,0xc7,0x92,0x02 +st %r21, [*%r17 subb %r18] +! CHECK: 0xba,0xc7,0x93,0x02 +st %r21, [*%r17 and %r18] +! CHECK: 0xba,0xc7,0x94,0x02 +st %r21, [*%r17 or %r18] +! CHECK: 0xba,0xc7,0x95,0x02 +st %r21, [*%r17 xor %r18] +! CHECK: 0xba,0xc7,0x96,0x02 +st %r21, [*%r17 sha %r18] +! CHECK: 0xba,0xc7,0x97,0xc2 +st.h %r21, [*%r17 add %r18] +! CHECK: 0xba,0xc7,0x90,0x00 +st.h %r21, [*%r17 addc %r18] +! CHECK: 0xba,0xc7,0x91,0x00 +st.h %r21, [*%r17 sub %r18] +! CHECK: 0xba,0xc7,0x92,0x00 +st.h %r21, [*%r17 subb %r18] +! CHECK: 0xba,0xc7,0x93,0x00 +st.h %r21, [*%r17 and %r18] +! CHECK: 0xba,0xc7,0x94,0x00 +st.h %r21, [*%r17 or %r18] +! CHECK: 0xba,0xc7,0x95,0x00 +st.h %r21, [*%r17 xor %r18] +! CHECK: 0xba,0xc7,0x96,0x00 +st.h %r21, [*%r17 sha %r18] +! CHECK: 0xba,0xc7,0x97,0xc0 +st.b %r21, [*%r17 add %r18] +! CHECK: 0xba,0xc7,0x90,0x04 +st.b %r21, [*%r17 addc %r18] +! CHECK: 0xba,0xc7,0x91,0x04 +st.b %r21, [*%r17 sub %r18] +! CHECK: 0xba,0xc7,0x92,0x04 +st.b %r21, [*%r17 subb %r18] +! CHECK: 0xba,0xc7,0x93,0x04 +st.b %r21, [*%r17 and %r18] +! CHECK: 0xba,0xc7,0x94,0x04 +st.b %r21, [*%r17 or %r18] +! CHECK: 0xba,0xc7,0x95,0x04 +st.b %r21, [*%r17 xor %r18] +! CHECK: 0xba,0xc7,0x96,0x04 +st.b %r21, [*%r17 sha %r18] +! CHECK: 0xba,0xc7,0x97,0xc4 +st %r21, [%r17* add %r18] +! CHECK: 0xba,0xc5,0x90,0x02 +st %r21, [%r17* addc %r18] +! CHECK: 0xba,0xc5,0x91,0x02 +st %r21, [%r17* sub %r18] +! CHECK: 0xba,0xc5,0x92,0x02 +st %r21, [%r17* subb %r18] +! CHECK: 0xba,0xc5,0x93,0x02 +st %r21, [%r17* and %r18] +! CHECK: 0xba,0xc5,0x94,0x02 +st %r21, [%r17* or %r18] +! CHECK: 0xba,0xc5,0x95,0x02 +st %r21, [%r17* xor %r18] +! CHECK: 0xba,0xc5,0x96,0x02 +st %r21, [%r17* sh %r18] +! CHECK: 0xba,0xc5,0x97,0x82 +st %r21, [%r17* sha %r18] +! CHECK: 0xba,0xc5,0x97,0xc2 +st.h %r21, [%r17* add %r18] +! CHECK: 0xba,0xc5,0x90,0x00 +st.h %r21, [%r17* addc %r18] +! CHECK: 0xba,0xc5,0x91,0x00 +st.h %r21, [%r17* sub %r18] +! CHECK: 0xba,0xc5,0x92,0x00 +st.h %r21, [%r17* subb %r18] +! CHECK: 0xba,0xc5,0x93,0x00 +st.h %r21, [%r17* and %r18] +! CHECK: 0xba,0xc5,0x94,0x00 +st.h %r21, [%r17* or %r18] +! CHECK: 0xba,0xc5,0x95,0x00 +st.h %r21, [%r17* xor %r18] +! CHECK: 0xba,0xc5,0x96,0x00 +st.h %r21, [%r17* sh %r18] +! CHECK: 0xba,0xc5,0x97,0x80 +st.h %r21, [%r17* sha %r18] +! CHECK: 0xba,0xc5,0x97,0xc0 +st.b %r21, [%r17* add %r18] +! CHECK: 0xba,0xc5,0x90,0x04 +st.b %r21, [%r17* addc %r18] +! CHECK: 0xba,0xc5,0x91,0x04 +st.b %r21, [%r17* sub %r18] +! CHECK: 0xba,0xc5,0x92,0x04 +st.b %r21, [%r17* subb %r18] +! CHECK: 0xba,0xc5,0x93,0x04 +st.b %r21, [%r17* and %r18] +! CHECK: 0xba,0xc5,0x94,0x04 +st.b %r21, [%r17* or %r18] +! CHECK: 0xba,0xc5,0x95,0x04 +st.b %r21, [%r17* xor %r18] +! CHECK: 0xba,0xc5,0x96,0x04 +st.b %r21, [%r17* sh %r18] +! CHECK: 0xba,0xc5,0x97,0x84 +st.b %r21, [%r17* sha %r18] +! CHECK: 0xba,0xc5,0x97,0xc4 +st %r21, [0x12344] +! CHECK: 0xfa,0x85,0x23,0x44 +sub %r17, 0, %r21 +! CHECK: 0x2a,0xc4,0x00,0x00 +sub %r17, 0x00001234, %r21 +! CHECK: 0x2a,0xc4,0x12,0x34 +sub %r17, 0x12340000, %r21 +! CHECK: 0x2a,0xc5,0x12,0x34 +sub.f %r17, 0, %r21 +! CHECK: 0x2a,0xc6,0x00,0x00 +sub.f %r17, 0x00001234, %r21 +! CHECK: 0x2a,0xc6,0x12,0x34 +sub.f %r17, 0x12340000, %r21 +! CHECK: 0x2a,0xc7,0x12,0x34 +sub %r17, %r18, %r21 +! CHECK: 0xca,0xc4,0x92,0x00 +sub.f %r17, %r18, %r21 +! CHECK: 0xca,0xc6,0x92,0x00 +subb %r17, 0, %r21 +! CHECK: 0x3a,0xc4,0x00,0x00 +subb %r17, 0x00001234, %r21 +! CHECK: 0x3a,0xc4,0x12,0x34 +subb %r17, 0x12340000, %r21 +! CHECK: 0x3a,0xc5,0x12,0x34 +subb.f %r17, 0, %r21 +! CHECK: 0x3a,0xc6,0x00,0x00 +subb.f %r17, 0x00001234, %r21 +! CHECK: 0x3a,0xc6,0x12,0x34 +subb.f %r17, 0x12340000, %r21 +! CHECK: 0x3a,0xc7,0x12,0x34 +subb %r17, %r18, %r21 +! CHECK: 0xca,0xc4,0x93,0x00 +subb.f %r17, %r18, %r21 +! CHECK: 0xca,0xc6,0x93,0x00 +xor %r17, 0, %r21 +! CHECK: 0x6a,0xc4,0x00,0x00 +xor %r17, 0x00001234, %r21 +! CHECK: 0x6a,0xc4,0x12,0x34 +xor %r17, 0x12340000, %r21 +! CHECK: 0x6a,0xc5,0x12,0x34 +xor.f %r17, 0, %r21 +! CHECK: 0x6a,0xc6,0x00,0x00 +xor.f %r17, 0x00001234, %r21 +! CHECK: 0x6a,0xc6,0x12,0x34 +xor.f %r17, 0x12340000, %r21 +! CHECK: 0x6a,0xc7,0x12,0x34 +xor %r17, %r18, %r21 +! CHECK: 0xca,0xc4,0x96,0x00 +xor.f %r17, %r18, %r21 +! CHECK: 0xca,0xc6,0x96,0x00 + + Index: test/Object/Lanai/yaml2obj-elf-lanai-rel.yaml =================================================================== --- test/Object/Lanai/yaml2obj-elf-lanai-rel.yaml +++ test/Object/Lanai/yaml2obj-elf-lanai-rel.yaml @@ -1,7 +1,7 @@ # RUN: yaml2obj -format=elf %s > %t # RUN: llvm-readobj -r %t | FileCheck %s -# CHECK : Relocations [ +# CHECK: Relocations [ # CHECK-NEXT: Section (2) .rel.text { # CHECK-NEXT: 0x0 R_LANAI_32 main 0x0 # CHECK-NEXT: 0x4 R_LANAI_NONE - 0x0