summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CODE_OWNERS.TXT4
-rw-r--r--lib/ObjectYAML/ELFYAML.cpp4
-rw-r--r--lib/Target/LLVMBuild.txt1
-rw-r--r--lib/Target/Lanai/AsmParser/CMakeLists.txt7
-rw-r--r--lib/Target/Lanai/AsmParser/LLVMBuild.txt23
-rw-r--r--lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp1162
-rw-r--r--lib/Target/Lanai/CMakeLists.txt36
-rw-r--r--lib/Target/Lanai/Disassembler/CMakeLists.txt3
-rw-r--r--lib/Target/Lanai/Disassembler/LLVMBuild.txt23
-rw-r--r--lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp228
-rw-r--r--lib/Target/Lanai/Disassembler/LanaiDisassembler.h41
-rw-r--r--lib/Target/Lanai/InstPrinter/CMakeLists.txt3
-rw-r--r--lib/Target/Lanai/InstPrinter/LLVMBuild.txt23
-rw-r--r--lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp309
-rw-r--r--lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h64
-rw-r--r--lib/Target/Lanai/LLVMBuild.txt45
-rw-r--r--lib/Target/Lanai/Lanai.h51
-rw-r--r--lib/Target/Lanai/Lanai.td47
-rw-r--r--lib/Target/Lanai/LanaiAluCode.h148
-rw-r--r--lib/Target/Lanai/LanaiAsmPrinter.cpp252
-rw-r--r--lib/Target/Lanai/LanaiCallingConv.td50
-rw-r--r--lib/Target/Lanai/LanaiCondCode.h100
-rw-r--r--lib/Target/Lanai/LanaiDelaySlotFiller.cpp250
-rw-r--r--lib/Target/Lanai/LanaiFrameLowering.cpp220
-rw-r--r--lib/Target/Lanai/LanaiFrameLowering.h57
-rw-r--r--lib/Target/Lanai/LanaiISelDAGToDAG.cpp325
-rw-r--r--lib/Target/Lanai/LanaiISelLowering.cpp1207
-rw-r--r--lib/Target/Lanai/LanaiISelLowering.h144
-rw-r--r--lib/Target/Lanai/LanaiInstrFormats.td561
-rw-r--r--lib/Target/Lanai/LanaiInstrInfo.cpp324
-rw-r--r--lib/Target/Lanai/LanaiInstrInfo.h126
-rw-r--r--lib/Target/Lanai/LanaiInstrInfo.td881
-rw-r--r--lib/Target/Lanai/LanaiMCInstLower.cpp139
-rw-r--r--lib/Target/Lanai/LanaiMCInstLower.h48
-rw-r--r--lib/Target/Lanai/LanaiMachineFunctionInfo.cpp23
-rw-r--r--lib/Target/Lanai/LanaiMachineFunctionInfo.h58
-rw-r--r--lib/Target/Lanai/LanaiMemAluCombiner.cpp414
-rw-r--r--lib/Target/Lanai/LanaiRegisterInfo.cpp282
-rw-r--r--lib/Target/Lanai/LanaiRegisterInfo.h63
-rw-r--r--lib/Target/Lanai/LanaiRegisterInfo.td64
-rw-r--r--lib/Target/Lanai/LanaiSchedule.td66
-rw-r--r--lib/Target/Lanai/LanaiSelectionDAGInfo.cpp33
-rw-r--r--lib/Target/Lanai/LanaiSelectionDAGInfo.h36
-rw-r--r--lib/Target/Lanai/LanaiSetflagAluCombiner.cpp327
-rw-r--r--lib/Target/Lanai/LanaiSubtarget.cpp48
-rw-r--r--lib/Target/Lanai/LanaiSubtarget.h76
-rw-r--r--lib/Target/Lanai/LanaiTargetMachine.cpp110
-rw-r--r--lib/Target/Lanai/LanaiTargetMachine.h54
-rw-r--r--lib/Target/Lanai/LanaiTargetObjectFile.cpp123
-rw-r--r--lib/Target/Lanai/LanaiTargetObjectFile.h46
-rw-r--r--lib/Target/Lanai/LanaiTargetTransformInfo.h87
-rw-r--r--lib/Target/Lanai/MCTargetDesc/CMakeLists.txt8
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LLVMBuild.txt23
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp168
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h145
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp95
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiFixupKinds.h43
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.cpp43
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.h32
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp325
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.cpp60
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.h56
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp163
-rw-r--r--lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h59
-rw-r--r--lib/Target/Lanai/TargetInfo/CMakeLists.txt3
-rw-r--r--lib/Target/Lanai/TargetInfo/LLVMBuild.txt23
-rw-r--r--lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp20
-rw-r--r--test/CodeGen/Lanai/codemodel.ll30
-rw-r--r--test/CodeGen/Lanai/combined_alu_setcc.ll126
-rw-r--r--test/CodeGen/Lanai/comparisons_i32.ll96
-rw-r--r--test/CodeGen/Lanai/constant_multiply.ll107
-rw-r--r--test/CodeGen/Lanai/delay_filler.ll41
-rw-r--r--test/CodeGen/Lanai/i32.ll145
-rw-r--r--test/CodeGen/Lanai/lit.local.cfg3
-rw-r--r--test/CodeGen/Lanai/mem_alu_combiner.ll40
-rw-r--r--test/CodeGen/Lanai/multiply.ll60
-rw-r--r--test/CodeGen/Lanai/select.ll41
-rw-r--r--test/CodeGen/Lanai/set_and_hi.ll15
-rw-r--r--test/CodeGen/Lanai/shift.ll28
-rw-r--r--test/CodeGen/Lanai/stack-frame.ll14
-rw-r--r--test/DebugInfo/Inputs/lanai-processes-relocations.elfbin1144 -> 0 bytes
-rw-r--r--test/DebugInfo/Lanai/processes-relocations.ll10
-rw-r--r--test/MC/Disassembler/Lanai/lit.local.cfg3
-rw-r--r--test/MC/Disassembler/Lanai/v11.txt762
-rw-r--r--test/MC/Lanai/lit.local.cfg3
-rw-r--r--test/MC/Lanai/v11.s830
-rw-r--r--test/Object/Lanai/yaml2obj-elf-lanai-rel.yaml2
87 files changed, 12430 insertions, 8 deletions
diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT
index 78072e4d288..24a41bc891e 100644
--- a/CODE_OWNERS.TXT
+++ b/CODE_OWNERS.TXT
@@ -142,6 +142,10 @@ N: Krzysztof Parzyszek
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
diff --git a/lib/ObjectYAML/ELFYAML.cpp b/lib/ObjectYAML/ELFYAML.cpp
index 3b94fa62e1d..8e39a24e4fe 100644
--- a/lib/ObjectYAML/ELFYAML.cpp
+++ b/lib/ObjectYAML/ELFYAML.cpp
@@ -194,6 +194,7 @@ ScalarEnumerationTraits<ELFYAML::ELF_EM>::enumeration(IO &IO,
ECase(EM_78KOR)
ECase(EM_56800EX)
ECase(EM_AMDGPU)
+ ECase(EM_LANAI)
#undef ECase
}
@@ -527,6 +528,9 @@ void ScalarEnumerationTraits<ELFYAML::ELF_REL>::enumeration(
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");
}
diff --git a/lib/Target/LLVMBuild.txt b/lib/Target/LLVMBuild.txt
index eb794ebc721..80676facbc7 100644
--- a/lib/Target/LLVMBuild.txt
+++ b/lib/Target/LLVMBuild.txt
@@ -25,6 +25,7 @@ subdirectories =
AVR
BPF
CppBackend
+ Lanai
Hexagon
MSP430
NVPTX
diff --git a/lib/Target/Lanai/AsmParser/CMakeLists.txt b/lib/Target/Lanai/AsmParser/CMakeLists.txt
new file mode 100644
index 00000000000..3c88192ea6f
--- /dev/null
+++ b/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 )
diff --git a/lib/Target/Lanai/AsmParser/LLVMBuild.txt b/lib/Target/Lanai/AsmParser/LLVMBuild.txt
new file mode 100644
index 00000000000..08cf4033087
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp b/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
new file mode 100644
index 00000000000..13f8779d6bd
--- /dev/null
+++ b/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
@@ -0,0 +1,1162 @@
+//===-- 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<LanaiOperand> parseRegister();
+
+ std::unique_ptr<LanaiOperand> parseImmediate();
+
+ std::unique_ptr<LanaiOperand> 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 isBrImm() {
+ if (!isImm())
+ return false;
+
+ // Constant case
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
+ int64_t Value = ConstExpr->getValue();
+ // Check if value fits in 25 bits with 2 least significant bits 0.
+ return isShiftedUInt<23, 2>(static_cast<int32_t>(Value));
+ }
+
+ // Symbolic reference expression
+ if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;
+
+ // Binary expression
+ if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))
+ if (const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;
+
+ return false;
+ }
+
+ bool isBrTarget() { return isBrImm() || isToken(); }
+
+ bool isCallTarget() { return isImm() || isToken(); }
+
+ bool isHiImm16() {
+ if (!isImm())
+ return false;
+
+ // Constant case
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
+ int64_t Value = ConstExpr->getValue();
+ return Value != 0 && isShiftedUInt<16, 16>(Value);
+ }
+
+ // Symbolic reference expression
+ if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI;
+
+ // Binary expression
+ if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))
+ if (const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI;
+
+ return false;
+ }
+
+ bool isHiImm16And() {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(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<MCConstantExpr>(Imm.Value)) {
+ int64_t Value = ConstExpr->getValue();
+ // Check if value fits in 16 bits
+ return isUInt<16>(static_cast<int32_t>(Value));
+ }
+
+ // Symbolic reference expression
+ if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
+
+ // Binary expression
+ if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))
+ if (const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(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<MCConstantExpr>(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<int32_t>(Value));
+ }
+
+ // Symbolic reference expression
+ if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
+
+ // Binary expression
+ if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))
+ if (const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
+
+ return false;
+ }
+
+ bool isLoImm16And() {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
+ if (ConstExpr) {
+ int64_t Value = ConstExpr->getValue();
+ // Check if in the form 0xffffXYZW
+ return ((Value & ~0xffff) == 0xffff0000);
+ }
+ return false;
+ }
+
+ bool isImmShift() {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
+ if (!ConstExpr)
+ return false;
+ int64_t Value = ConstExpr->getValue();
+ return (Value >= -31) && (Value <= 31);
+ }
+
+ bool isLoImm21() {
+ if (!isImm())
+ return false;
+
+ // Constant case
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
+ int64_t Value = ConstExpr->getValue();
+ return isUInt<21>(Value);
+ }
+
+ // Symbolic reference expression
+ if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;
+ if (const MCSymbolRefExpr *SymbolRefExpr =
+ dyn_cast<MCSymbolRefExpr>(Imm.Value)) {
+ return SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None;
+ }
+
+ // Binary expression
+ if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value)) {
+ if (const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;
+ if (const MCSymbolRefExpr *SymbolRefExpr =
+ dyn_cast<MCSymbolRefExpr>(BinaryExpr->getLHS()))
+ return SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None;
+ }
+
+ return false;
+ }
+
+ bool isImm10() {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(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 == nullptr)
+ Inst.addOperand(MCOperand::createImm(0));
+ else if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Expr))
+ Inst.addOperand(
+ MCOperand::createImm(static_cast<int32_t>(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 addImmShiftOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ addExpr(Inst, getImm());
+ }
+
+ 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<MCConstantExpr>(getImm()))
+ Inst.addOperand(
+ MCOperand::createImm(static_cast<int32_t>(ConstExpr->getValue())));
+ else if (isa<LanaiMCExpr>(getImm())) {
+#ifndef NDEBUG
+ const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());
+ assert(SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else if (isa<MCBinaryExpr>(getImm())) {
+#ifndef NDEBUG
+ const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());
+ assert(dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()) &&
+ dyn_cast<LanaiMCExpr>(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<MCConstantExpr>(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<MCConstantExpr>(getImm()))
+ Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16));
+ else if (isa<LanaiMCExpr>(getImm())) {
+#ifndef NDEBUG
+ const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());
+ assert(SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else if (isa<MCBinaryExpr>(getImm())) {
+#ifndef NDEBUG
+ const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());
+ assert(dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()) &&
+ dyn_cast<LanaiMCExpr>(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<MCConstantExpr>(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<MCConstantExpr>(getImm()))
+ Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0x1fffff));
+ else if (isa<LanaiMCExpr>(getImm())) {
+#ifndef NDEBUG
+ const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());
+ assert(SymbolRefExpr &&
+ SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else if (isa<MCSymbolRefExpr>(getImm())) {
+#ifndef NDEBUG
+ const MCSymbolRefExpr *SymbolRefExpr =
+ dyn_cast<MCSymbolRefExpr>(getImm());
+ assert(SymbolRefExpr &&
+ SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else if (isa<MCBinaryExpr>(getImm())) {
+#ifndef NDEBUG
+ const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());
+ const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(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<LanaiOperand> CreateToken(StringRef Str, SMLoc Start) {
+ auto Op = make_unique<LanaiOperand>(TOKEN);
+ Op->Tok.Data = Str.data();
+ Op->Tok.Length = Str.size();
+ Op->StartLoc = Start;
+ Op->EndLoc = Start;
+ return Op;
+ }
+
+ static std::unique_ptr<LanaiOperand> createReg(unsigned RegNum, SMLoc Start,
+ SMLoc End) {
+ auto Op = make_unique<LanaiOperand>(REGISTER);
+ Op->Reg.RegNum = RegNum;
+ Op->StartLoc = Start;
+ Op->EndLoc = End;
+ return Op;
+ }
+
+ static std::unique_ptr<LanaiOperand> createImm(const MCExpr *Value,
+ SMLoc Start, SMLoc End) {
+ auto Op = make_unique<LanaiOperand>(IMMEDIATE);
+ Op->Imm.Value = Value;
+ Op->StartLoc = Start;
+ Op->EndLoc = End;
+ return Op;
+ }
+
+ static std::unique_ptr<LanaiOperand>
+ MorphToMemImm(std::unique_ptr<LanaiOperand> 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<LanaiOperand>
+ MorphToMemRegReg(unsigned BaseReg, std::unique_ptr<LanaiOperand> 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<LanaiOperand>
+ MorphToMemRegImm(unsigned BaseReg, std::unique_ptr<LanaiOperand> 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<LanaiOperand> 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<LanaiOperand> Op = parseRegister();
+ if (Op != 0)
+ RegNum = Op->getReg();
+ return (Op == 0);
+}
+
+std::unique_ptr<LanaiOperand> 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<LanaiOperand> 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;
+ }
+}
+
+static 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;
+}
+
+static int SizeForSuffix(StringRef T) {
+ return StringSwitch<int>(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<MCConstantExpr>(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<LanaiMCExpr>(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<MCBinaryExpr>(Op.getImm())) {
+ const LanaiMCExpr *LHSSymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(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<LanaiOperand *>(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<LanaiOperand> 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<LanaiOperand> 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<LanaiOperand> 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<LanaiOperand *>(Operands[PossibleAluOpIdx].get()))
+ if (PossibleAluOp->isImm())
+ if (const MCConstantExpr *ConstExpr =
+ dyn_cast<MCConstantExpr>(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">, <LPCC:ICC_T>
+ 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<LanaiAsmParser> x(TheLanaiTarget);
+}
+
+} // namespace llvm
diff --git a/lib/Target/Lanai/CMakeLists.txt b/lib/Target/Lanai/CMakeLists.txt
new file mode 100644
index 00000000000..e5aec96e476
--- /dev/null
+++ b/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)
diff --git a/lib/Target/Lanai/Disassembler/CMakeLists.txt b/lib/Target/Lanai/Disassembler/CMakeLists.txt
new file mode 100644
index 00000000000..785c98d8dff
--- /dev/null
+++ b/lib/Target/Lanai/Disassembler/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_llvm_library(LLVMLanaiDisassembler
+ LanaiDisassembler.cpp
+ )
diff --git a/lib/Target/Lanai/Disassembler/LLVMBuild.txt b/lib/Target/Lanai/Disassembler/LLVMBuild.txt
new file mode 100644
index 00000000000..fe789f90f2e
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp b/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
new file mode 100644
index 00000000000..3a71b80b2ba
--- /dev/null
+++ b/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
@@ -0,0 +1,228 @@
+//===- LanaiDisassembler.cpp - Disassembler for Lanai -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the Lanai Disassembler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LanaiDisassembler.h"
+
+#include "Lanai.h"
+#include "LanaiSubtarget.h"
+#include "llvm/MC/MCFixedLenDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryObject.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+typedef MCDisassembler::DecodeStatus DecodeStatus;
+
+namespace llvm {
+extern Target TheLanaiTarget;
+}
+
+static MCDisassembler *createLanaiDisassembler(const Target &T,
+ const MCSubtargetInfo &STI,
+ MCContext &Ctx) {
+ return new LanaiDisassembler(STI, Ctx);
+}
+
+extern "C" void LLVMInitializeLanaiDisassembler() {
+ // Register the disassembler
+ TargetRegistry::RegisterMCDisassembler(TheLanaiTarget,
+ createLanaiDisassembler);
+}
+
+LanaiDisassembler::LanaiDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
+ : MCDisassembler(STI, Ctx) {}
+
+// Forward declare because the autogenerated code will reference this.
+// Definition is further down.
+DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
+
+static DecodeStatus decodeRiMemoryValue(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+
+static DecodeStatus decodeRrMemoryValue(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+
+static DecodeStatus decodeSplsValue(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+
+static DecodeStatus decodeBranch(MCInst &Inst, unsigned Insn, uint64_t Address,
+ const void *Decoder);
+
+static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder);
+
+#include "LanaiGenDisassemblerTables.inc"
+
+static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
+ uint64_t &Size, uint32_t &Insn) {
+ // We want to read exactly 4 bytes of data.
+ if (Bytes.size() < 4) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ // Encoded as big-endian 32-bit word in the stream.
+ Insn =
+ (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 8) | (Bytes[3] << 0);
+
+ return MCDisassembler::Success;
+}
+
+static void PostOperandDecodeAdjust(MCInst &Instr, uint32_t Insn) {
+ unsigned AluOp = LPAC::ADD;
+ // Fix up for pre and post operations.
+ int PqShift = -1;
+ if (isRMOpcode(Instr.getOpcode()))
+ PqShift = 16;
+ else if (isSPLSOpcode(Instr.getOpcode()))
+ PqShift = 10;
+ else if (isRRMOpcode(Instr.getOpcode())) {
+ PqShift = 16;
+ // Determine RRM ALU op.
+ AluOp = (Insn >> 8) & 0x7;
+ if (AluOp == 7)
+ // Handle JJJJJ
+ // 0b10000 or 0b11000
+ AluOp |= 0x20 | (((Insn >> 3) & 0xf) << 1);
+ }
+
+ if (PqShift != -1) {
+ unsigned PQ = (Insn >> PqShift) & 0x3;
+ switch (PQ) {
+ case 0x0:
+ if (Instr.getOperand(2).isReg()) {
+ Instr.getOperand(2).setReg(Lanai::R0);
+ }
+ if (Instr.getOperand(2).isImm())
+ Instr.getOperand(2).setImm(0);
+ break;
+ case 0x1:
+ AluOp = LPAC::makePostOp(AluOp);
+ break;
+ case 0x2:
+ break;
+ case 0x3:
+ AluOp = LPAC::makePreOp(AluOp);
+ break;
+ }
+ Instr.addOperand(MCOperand::createImm(AluOp));
+ }
+}
+
+DecodeStatus LanaiDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const {
+ uint32_t Insn;
+
+ DecodeStatus Result = readInstruction32(Bytes, Address, Size, Insn);
+
+ if (Result == MCDisassembler::Fail)
+ return MCDisassembler::Fail;
+
+ // Call auto-generated decoder function
+ Result =
+ decodeInstruction(DecoderTableLanai32, Instr, Insn, Address, this, STI);
+
+ if (Result != MCDisassembler::Fail) {
+ PostOperandDecodeAdjust(Instr, Insn);
+ Size = 4;
+ return Result;
+ }
+
+ return MCDisassembler::Fail;
+}
+
+static const unsigned GPRDecoderTable[] = {
+ Lanai::R0, Lanai::R1, Lanai::PC, Lanai::R3, Lanai::SP, Lanai::FP,
+ Lanai::R6, Lanai::R7, Lanai::RV, Lanai::R9, Lanai::RR1, Lanai::RR2,
+ Lanai::R12, Lanai::R13, Lanai::R14, Lanai::RCA, Lanai::R16, Lanai::R17,
+ Lanai::R18, Lanai::R19, Lanai::R20, Lanai::R21, Lanai::R22, Lanai::R23,
+ Lanai::R24, Lanai::R25, Lanai::R26, Lanai::R27, Lanai::R28, Lanai::R29,
+ Lanai::R30, Lanai::R31};
+
+DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+
+ unsigned Reg = GPRDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeRiMemoryValue(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ // RI memory values encoded using 23 bits:
+ // 5 bit register, 16 bit constant
+ unsigned Register = (Insn >> 18) & 0x1f;
+ Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));
+ unsigned Offset = (Insn & 0xffff);
+ Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset)));
+
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeRrMemoryValue(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ // RR memory values encoded using 20 bits:
+ // 5 bit register, 5 bit register, 2 bit PQ, 3 bit ALU operator, 5 bit JJJJJ
+ unsigned Register = (Insn >> 15) & 0x1f;
+ Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));
+ Register = (Insn >> 10) & 0x1f;
+ Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));
+
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeSplsValue(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ // RI memory values encoded using 17 bits:
+ // 5 bit register, 10 bit constant
+ unsigned Register = (Insn >> 12) & 0x1f;
+ Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));
+ unsigned Offset = (Insn & 0x3ff);
+ Inst.addOperand(MCOperand::createImm(SignExtend32<10>(Offset)));
+
+ return MCDisassembler::Success;
+}
+
+static bool tryAddingSymbolicOperand(int64_t Value, bool IsBranch,
+ uint64_t Address, uint64_t Offset,
+ uint64_t Width, MCInst &MI,
+ const void *Decoder) {
+ const MCDisassembler *Dis = static_cast<const MCDisassembler *>(Decoder);
+ return Dis->tryAddingSymbolicOperand(MI, Value, Address, IsBranch, Offset,
+ Width);
+}
+
+static DecodeStatus decodeBranch(MCInst &MI, unsigned Insn, uint64_t Address,
+ const void *Decoder) {
+ if (!tryAddingSymbolicOperand(Insn + Address, false, Address, 2, 23, MI,
+ Decoder))
+ MI.addOperand(MCOperand::createImm(Insn));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned Offset = (Insn & 0xffff);
+ Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset)));
+
+ return MCDisassembler::Success;
+}
diff --git a/lib/Target/Lanai/Disassembler/LanaiDisassembler.h b/lib/Target/Lanai/Disassembler/LanaiDisassembler.h
new file mode 100644
index 00000000000..a317cd88ad6
--- /dev/null
+++ b/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<uint8_t> Bytes,
+ uint64_t Address, raw_ostream &VStream,
+ raw_ostream &CStream) const override;
+};
+
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_LANAI_DISASSEMBLER_LANAIDISASSEMBLER_H
diff --git a/lib/Target/Lanai/InstPrinter/CMakeLists.txt b/lib/Target/Lanai/InstPrinter/CMakeLists.txt
new file mode 100644
index 00000000000..6badb1c98a6
--- /dev/null
+++ b/lib/Target/Lanai/InstPrinter/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_llvm_library(LLVMLanaiInstPrinter
+ LanaiInstPrinter.cpp
+ )
diff --git a/lib/Target/Lanai/InstPrinter/LLVMBuild.txt b/lib/Target/Lanai/InstPrinter/LLVMBuild.txt
new file mode 100644
index 00000000000..6366d7eded8
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp b/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp
new file mode 100644
index 00000000000..6460b88d142
--- /dev/null
+++ b/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp
@@ -0,0 +1,309 @@
+//===-- LanaiInstPrinter.cpp - Convert Lanai MCInst to asm syntax ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class prints an Lanai MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Lanai.h"
+#include "LanaiInstPrinter.h"
+#include "MCTargetDesc/LanaiMCExpr.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormattedStream.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "asm-printer"
+
+// Include the auto-generated portion of the assembly writer.
+#define PRINT_ALIAS_INSTR
+#include "LanaiGenAsmWriter.inc"
+
+void LanaiInstPrinter::printRegName(raw_ostream &Ostream,
+ unsigned RegNo) const {
+ Ostream << StringRef(getRegisterName(RegNo)).lower();
+}
+
+bool LanaiInstPrinter::printInst(const MCInst *MI, raw_ostream &Ostream,
+ StringRef Alias, unsigned OpNo0,
+ unsigned OpNo1) {
+ Ostream << "\t" << Alias << " ";
+ printOperand(MI, OpNo0, Ostream);
+ Ostream << ", ";
+ printOperand(MI, OpNo1, Ostream);
+ return true;
+}
+
+static bool usesGivenOffset(const MCInst *MI, int AddOffset) {
+ unsigned AluCode = MI->getOperand(3).getImm();
+ return LPAC::encodeLanaiAluCode(AluCode) == LPAC::ADD &&
+ (MI->getOperand(2).getImm() == AddOffset ||
+ MI->getOperand(2).getImm() == -AddOffset);
+}
+
+static bool isPreIncrementForm(const MCInst *MI, int AddOffset) {
+ unsigned AluCode = MI->getOperand(3).getImm();
+ return LPAC::isPreOp(AluCode) && usesGivenOffset(MI, AddOffset);
+}
+
+static bool isPostIncrementForm(const MCInst *MI, int AddOffset) {
+ unsigned AluCode = MI->getOperand(3).getImm();
+ return LPAC::isPostOp(AluCode) && usesGivenOffset(MI, AddOffset);
+}
+
+static StringRef decIncOperator(const MCInst *MI) {
+ if (MI->getOperand(2).getImm() < 0)
+ return "--";
+ return "++";
+}
+
+bool LanaiInstPrinter::printMemoryLoadIncrement(const MCInst *MI,
+ raw_ostream &Ostream,
+ StringRef Opcode,
+ int AddOffset) {
+ if (isPreIncrementForm(MI, AddOffset)) {
+ Ostream << "\t" << Opcode << "\t[" << decIncOperator(MI) << "%"
+ << getRegisterName(MI->getOperand(1).getReg()) << "], %"
+ << getRegisterName(MI->getOperand(0).getReg());
+ return true;
+ }
+ if (isPostIncrementForm(MI, AddOffset)) {
+ Ostream << "\t" << Opcode << "\t[%"
+ << getRegisterName(MI->getOperand(1).getReg()) << decIncOperator(MI)
+ << "], %" << getRegisterName(MI->getOperand(0).getReg());
+ return true;
+ }
+ return false;
+}
+
+bool LanaiInstPrinter::printMemoryStoreIncrement(const MCInst *MI,
+ raw_ostream &Ostream,
+ StringRef Opcode,
+ int AddOffset) {
+ if (isPreIncrementForm(MI, AddOffset)) {
+ Ostream << "\t" << Opcode << "\t%"
+ << getRegisterName(MI->getOperand(0).getReg()) << ", ["
+ << decIncOperator(MI) << "%"
+ << getRegisterName(MI->getOperand(1).getReg()) << "]";
+ return true;
+ }
+ if (isPostIncrementForm(MI, AddOffset)) {
+ Ostream << "\t" << Opcode << "\t%"
+ << getRegisterName(MI->getOperand(0).getReg()) << ", [%"
+ << getRegisterName(MI->getOperand(1).getReg()) << decIncOperator(MI)
+ << "]";
+ return true;
+ }
+ return false;
+}
+
+bool LanaiInstPrinter::printAlias(const MCInst *MI, raw_ostream &Ostream) {
+ switch (MI->getOpcode()) {
+ case Lanai::LDW_RI:
+ // ld 4[*%rN], %rX => ld [++imm], %rX
+ // ld -4[*%rN], %rX => ld [--imm], %rX
+ // ld 4[%rN*], %rX => ld [imm++], %rX
+ // ld -4[%rN*], %rX => ld [imm--], %rX
+ return printMemoryLoadIncrement(MI, Ostream, "ld", 4);
+ case Lanai::LDHs_RI:
+ return printMemoryLoadIncrement(MI, Ostream, "ld.h", 2);
+ case Lanai::LDHz_RI:
+ return printMemoryLoadIncrement(MI, Ostream, "uld.h", 2);
+ case Lanai::LDBs_RI:
+ return printMemoryLoadIncrement(MI, Ostream, "ld.b", 1);
+ case Lanai::LDBz_RI:
+ return printMemoryLoadIncrement(MI, Ostream, "uld.b", 1);
+ case Lanai::SW_RI:
+ // st %rX, 4[*%rN] => st %rX, [++imm]
+ // st %rX, -4[*%rN] => st %rX, [--imm]
+ // st %rX, 4[%rN*] => st %rX, [imm++]
+ // st %rX, -4[%rN*] => st %rX, [imm--]
+ return printMemoryStoreIncrement(MI, Ostream, "st", 4);
+ case Lanai::STH_RI:
+ return printMemoryStoreIncrement(MI, Ostream, "st.h", 2);
+ case Lanai::STB_RI:
+ return printMemoryStoreIncrement(MI, Ostream, "st.b", 1);
+ default:
+ return false;
+ }
+}
+
+void LanaiInstPrinter::printInst(const MCInst *MI, raw_ostream &Ostream,
+ StringRef Annotation,
+ const MCSubtargetInfo &STI) {
+ if (!printAlias(MI, Ostream) && !printAliasInstr(MI, Ostream))
+ printInstruction(MI, Ostream);
+ printAnnotation(Ostream, Annotation);
+}
+
+static void printExpr(const MCAsmInfo &MAI, const MCExpr &Expr,
+ raw_ostream &Ostream) {
+ const MCExpr *SRE;
+
+ if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(&Expr))
+ SRE = dyn_cast<LanaiMCExpr>(BE->getLHS());
+ else if (isa<LanaiMCExpr>(&Expr)) {
+ SRE = dyn_cast<LanaiMCExpr>(&Expr);
+ } else {
+ SRE = dyn_cast<MCSymbolRefExpr>(&Expr);
+ }
+ assert(SRE && "Unexpected MCExpr type.");
+
+ SRE->print(Ostream, &MAI);
+}
+
+void LanaiInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &Ostream,
+ const char *Modifier) {
+ assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
+ const MCOperand &Op = MI->getOperand(OpNo);
+ if (Op.isReg())
+ Ostream << "%" << getRegisterName(Op.getReg());
+ else if (Op.isImm())
+ Ostream << formatHex(Op.getImm());
+ else {
+ assert(Op.isExpr() && "Expected an expression");
+ printExpr(MAI, *Op.getExpr(), Ostream);
+ }
+}
+
+void LanaiInstPrinter::printMemImmOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &Ostream) {
+ const MCOperand &Op = MI->getOperand(OpNo);
+ if (Op.isImm()) {
+ Ostream << '[' << formatHex(Op.getImm()) << ']';
+ } else {
+ // Symbolic operand will be lowered to immediate value by linker
+ assert(Op.isExpr() && "Expected an expression");
+ Ostream << '[';
+ printExpr(MAI, *Op.getExpr(), Ostream);
+ Ostream << ']';
+ }
+}
+
+void LanaiInstPrinter::printHi16ImmOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &Ostream) {
+ const MCOperand &Op = MI->getOperand(OpNo);
+ if (Op.isImm()) {
+ Ostream << formatHex(Op.getImm() << 16);
+ } else {
+ // Symbolic operand will be lowered to immediate value by linker
+ assert(Op.isExpr() && "Expected an expression");
+ printExpr(MAI, *Op.getExpr(), Ostream);
+ }
+}
+
+void LanaiInstPrinter::printHi16AndImmOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &Ostream) {
+ const MCOperand &Op = MI->getOperand(OpNo);
+ if (Op.isImm()) {
+ Ostream << formatHex((Op.getImm() << 16) | 0xffff);
+ } else {
+ // Symbolic operand will be lowered to immediate value by linker
+ assert(Op.isExpr() && "Expected an expression");
+ printExpr(MAI, *Op.getExpr(), Ostream);
+ }
+}
+
+void LanaiInstPrinter::printLo16AndImmOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &Ostream) {
+ const MCOperand &Op = MI->getOperand(OpNo);
+ if (Op.isImm()) {
+ Ostream << formatHex(0xffff0000 | Op.getImm());
+ } else {
+ // Symbolic operand will be lowered to immediate value by linker
+ assert(Op.isExpr() && "Expected an expression");
+ printExpr(MAI, *Op.getExpr(), Ostream);
+ }
+}
+
+static void printMemoryBaseRegister(raw_ostream &Ostream, const unsigned AluCode,
+ const MCOperand &RegOp) {
+ assert(RegOp.isReg() && "Register operand expected");
+ Ostream << "[";
+ if (LPAC::isPreOp(AluCode))
+ Ostream << "*";
+ Ostream << "%" << LanaiInstPrinter::getRegisterName(RegOp.getReg());
+ if (LPAC::isPostOp(AluCode))
+ Ostream << "*";
+ Ostream << "]";
+}
+
+template <unsigned SizeInBits>
+static void printMemoryImmediateOffset(const MCAsmInfo &MAI,
+ const MCOperand &OffsetOp,
+ raw_ostream &Ostream) {
+ assert((OffsetOp.isImm() || OffsetOp.isExpr()) && "Immediate expected");
+ if (OffsetOp.isImm()) {
+ assert(isInt<SizeInBits>(OffsetOp.getImm()) && "Constant value truncated");
+ Ostream << OffsetOp.getImm();
+ } else
+ printExpr(MAI, *OffsetOp.getExpr(), Ostream);
+}
+
+void LanaiInstPrinter::printMemRiOperand(const MCInst *MI, int OpNo,
+ raw_ostream &Ostream,
+ const char *Modifier) {
+ const MCOperand &RegOp = MI->getOperand(OpNo);
+ const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
+ const MCOperand &AluOp = MI->getOperand(OpNo + 2);
+ const unsigned AluCode = AluOp.getImm();
+
+ // Offset
+ printMemoryImmediateOffset<16>(MAI, OffsetOp, Ostream);
+
+ // Register
+ printMemoryBaseRegister(Ostream, AluCode, RegOp);
+}
+
+void LanaiInstPrinter::printMemRrOperand(const MCInst *MI, int OpNo,
+ raw_ostream &Ostream,
+ const char *Modifier) {
+ const MCOperand &RegOp = MI->getOperand(OpNo);
+ const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
+ const MCOperand &AluOp = MI->getOperand(OpNo + 2);
+ const unsigned AluCode = AluOp.getImm();
+ assert(OffsetOp.isReg() && RegOp.isReg() && "Registers expected.");
+
+ // [ Base OP Offset ]
+ Ostream << "[";
+ if (LPAC::isPreOp(AluCode))
+ Ostream << "*";
+ Ostream << "%" << getRegisterName(RegOp.getReg());
+ if (LPAC::isPostOp(AluCode))
+ Ostream << "*";
+ Ostream << " " << LPAC::lanaiAluCodeToString(AluCode) << " ";
+ Ostream << "%" << getRegisterName(OffsetOp.getReg());
+ Ostream << "]";
+}
+
+void LanaiInstPrinter::printMemSplsOperand(const MCInst *MI, int OpNo,
+ raw_ostream &Ostream,
+ const char *Modifier) {
+ const MCOperand &RegOp = MI->getOperand(OpNo);
+ const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
+ const MCOperand &AluOp = MI->getOperand(OpNo + 2);
+ const unsigned AluCode = AluOp.getImm();
+
+ // Offset
+ printMemoryImmediateOffset<10>(MAI, OffsetOp, Ostream);
+
+ // Register
+ printMemoryBaseRegister(Ostream, AluCode, RegOp);
+}
+
+void LanaiInstPrinter::printCCOperand(const MCInst *MI, int OpNo,
+ raw_ostream &Ostream) {
+ const int CC = static_cast<const int>(MI->getOperand(OpNo).getImm());
+ Ostream << lanaiCondCodeToString(static_cast<LPCC::CondCode>(CC));
+}
diff --git a/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h b/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
new file mode 100644
index 00000000000..4bd5bb0e7fc
--- /dev/null
+++ b/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
@@ -0,0 +1,64 @@
+//= LanaiInstPrinter.h - Convert Lanai MCInst to asm syntax -------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class prints a Lanai MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H
+#define LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H
+
+#include "llvm/MC/MCInstPrinter.h"
+
+namespace llvm {
+class MCOperand;
+
+class LanaiInstPrinter : public MCInstPrinter {
+public:
+ LanaiInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
+ const MCRegisterInfo &MRI)
+ : MCInstPrinter(MAI, MII, MRI) {}
+
+ void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
+ const MCSubtargetInfo &STI) override;
+ void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O,
+ const char *Modifier = 0);
+ void printMemRiOperand(const MCInst *MI, int OpNo, raw_ostream &O,
+ const char *Modifier = 0);
+ void printMemRrOperand(const MCInst *MI, int OpNo, raw_ostream &O,
+ const char *Modifier = 0);
+ void printMemSplsOperand(const MCInst *MI, int OpNo, raw_ostream &O,
+ const char *Modifier = 0);
+ void printCCOperand(const MCInst *MI, int OpNo, raw_ostream &O);
+ void printAluOperand(const MCInst *MI, int OpNo, raw_ostream &O);
+ void printHi16ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printHi16AndImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printLo16AndImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+ void printMemImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
+
+ // Autogenerated by tblgen.
+ void printInstruction(const MCInst *MI, raw_ostream &O);
+ bool printAliasInstr(const MCInst *MI, raw_ostream &OS);
+ void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx,
+ unsigned PrintMethodIdx, raw_ostream &O);
+ static const char *getRegisterName(unsigned RegNo);
+ void printRegName(raw_ostream &OS, unsigned RegNo) const override;
+
+private:
+ bool printAlias(const MCInst *MI, raw_ostream &Ostream);
+ bool printInst(const MCInst *MI, raw_ostream &Ostream, StringRef Alias,
+ unsigned OpNo0, unsigned OpnNo1);
+ bool printMemoryLoadIncrement(const MCInst *MI, raw_ostream &Ostream,
+ StringRef Opcode, int AddOffset);
+ bool printMemoryStoreIncrement(const MCInst *MI, raw_ostream &Ostream,
+ StringRef Opcode, int AddOffset);
+};
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H
diff --git a/lib/Target/Lanai/LLVMBuild.txt b/lib/Target/Lanai/LLVMBuild.txt
new file mode 100644
index 00000000000..91accbbfb76
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/Lanai.h b/lib/Target/Lanai/Lanai.h
new file mode 100644
index 00000000000..47bd498c579
--- /dev/null
+++ b/lib/Target/Lanai/Lanai.h
@@ -0,0 +1,51 @@
+//===-- Lanai.h - Top-level interface for Lanai representation --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the entry points for global functions defined in the LLVM
+// Lanai back-end.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_LANAI_LANAI_H
+#define LLVM_LIB_TARGET_LANAI_LANAI_H
+
+#include "LanaiAluCode.h"
+#include "LanaiCondCode.h"
+#include "MCTargetDesc/LanaiBaseInfo.h"
+#include "MCTargetDesc/LanaiMCTargetDesc.h"
+#include "llvm/CodeGen/ISDOpcodes.h"
+#include "llvm/Target/TargetMachine.h"
+
+namespace llvm {
+class FunctionPass;
+class LanaiTargetMachine;
+class MachineFunctionPass;
+class TargetMachine;
+class formatted_raw_ostream;
+
+// createLanaiISelDag - This pass converts a legalized DAG into a
+// Lanai-specific DAG, ready for instruction scheduling.
+FunctionPass *createLanaiISelDag(LanaiTargetMachine &TM);
+
+// createLanaiDelaySlotFillerPass - This pass fills delay slots
+// with useful instructions or nop's
+FunctionPass *createLanaiDelaySlotFillerPass(const LanaiTargetMachine &TM);
+
+// createLanaiMemAluCombinerPass - This pass combines loads/stores and
+// arithmetic operations.
+FunctionPass *createLanaiMemAluCombinerPass();
+
+// createLanaiSetflagAluCombinerPass - This pass combines SET_FLAG and ALU
+// operations.
+FunctionPass *createLanaiSetflagAluCombinerPass();
+
+extern Target TheLanaiTarget;
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_LANAI_LANAI_H
diff --git a/lib/Target/Lanai/Lanai.td b/lib/Target/Lanai/Lanai.td
new file mode 100644
index 00000000000..73d08045703
--- /dev/null
+++ b/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];
+}
diff --git a/lib/Target/Lanai/LanaiAluCode.h b/lib/Target/Lanai/LanaiAluCode.h
new file mode 100644
index 00000000000..b6ceedef665
--- /dev/null
+++ b/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<AluCode>(S)
+ .Case("add", ADD)
+ .Case("addc", ADDC)
+ .Case("sub", SUB)
+ .Case("subb", SUBB)
+ .Case("and", AND)
+ .Case("or", OR)
+ .Case("xor", XOR)
+ .Case("sh", SHL)
+ .Case("srl", SRL)
+ .Case("sha", SRA)
+ .Default(UNKNOWN);
+}
+
+inline static AluCode isdToLanaiAluCode(ISD::NodeType Node_type) {
+ switch (Node_type) {
+ case ISD::ADD:
+ return AluCode::ADD;
+ case ISD::ADDE:
+ return AluCode::ADDC;
+ case ISD::SUB:
+ return AluCode::SUB;
+ case ISD::SUBE:
+ return AluCode::SUBB;
+ case ISD::AND:
+ return AluCode::AND;
+ case ISD::OR:
+ return AluCode::OR;
+ case ISD::XOR:
+ return AluCode::XOR;
+ case ISD::SHL:
+ return AluCode::SHL;
+ case ISD::SRL:
+ return AluCode::SRL;
+ case ISD::SRA:
+ return AluCode::SRA;
+ default:
+ return AluCode::UNKNOWN;
+ }
+}
+} // namespace LPAC
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_LANAI_LANAIALUCODE_H
diff --git a/lib/Target/Lanai/LanaiAsmPrinter.cpp b/lib/Target/Lanai/LanaiAsmPrinter.cpp
new file mode 100644
index 00000000000..27a5e9eabb5
--- /dev/null
+++ b/lib/Target/Lanai/LanaiAsmPrinter.cpp
@@ -0,0 +1,252 @@
+//===-- LanaiAsmPrinter.cpp - Lanai LLVM assembly writer ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a printer that converts from our internal representation
+// of machine-dependent LLVM code to the Lanai assembly language.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Lanai.h"
+#include "InstPrinter/LanaiInstPrinter.h"
+#include "LanaiInstrInfo.h"
+#include "LanaiMCInstLower.h"
+#include "LanaiTargetMachine.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Module.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "asm-printer"
+
+using namespace llvm;
+
+namespace {
+class LanaiAsmPrinter : public AsmPrinter {
+public:
+ explicit LanaiAsmPrinter(TargetMachine &TM,
+ std::unique_ptr<MCStreamer> Streamer)
+ : AsmPrinter(TM, std::move(Streamer)) {}
+
+ const char *getPassName() const override { return "Lanai Assembly Printer"; }
+
+ void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O,
+ const char *Modifier = 0);
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) override;
+ void EmitInstruction(const MachineInstr *MI) override;
+ bool isBlockOnlyReachableByFallthrough(
+ const MachineBasicBlock *MBB) const override;
+
+private:
+ void customEmitInstruction(const MachineInstr *MI);
+ void emitCallInstruction(const MachineInstr *MI);
+};
+} // end of anonymous namespace
+
+void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
+ raw_ostream &O, const char *Modifier) {
+ const MachineOperand &MO = MI->getOperand(OpNum);
+ unsigned TF = MO.getTargetFlags();
+
+ switch (MO.getType()) {
+ case MachineOperand::MO_Register:
+ O << LanaiInstPrinter::getRegisterName(MO.getReg());
+ break;
+
+ case MachineOperand::MO_Immediate:
+ O << MO.getImm();
+ break;
+
+ case MachineOperand::MO_MachineBasicBlock:
+ O << *MO.getMBB()->getSymbol();
+ break;
+
+ case MachineOperand::MO_GlobalAddress:
+ if (TF == LanaiII::MO_PLT)
+ O << "plt(" << *getSymbol(MO.getGlobal()) << ")";
+ else
+ O << *getSymbol(MO.getGlobal());
+ break;
+
+ case MachineOperand::MO_BlockAddress: {
+ MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
+ O << BA->getName();
+ break;
+ }
+
+ case MachineOperand::MO_ExternalSymbol:
+ if (TF == LanaiII::MO_PLT)
+ O << "plt(" << *GetExternalSymbolSymbol(MO.getSymbolName()) << ")";
+ else
+ O << *GetExternalSymbolSymbol(MO.getSymbolName());
+ break;
+
+ case MachineOperand::MO_JumpTableIndex:
+ O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_'
+ << MO.getIndex();
+ break;
+
+ case MachineOperand::MO_ConstantPoolIndex:
+ O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_'
+ << MO.getIndex();
+ return;
+
+ default:
+ llvm_unreachable("<unknown operand type>");
+ }
+}
+
+// PrintAsmOperand - Print out an operand for an inline asm expression.
+//
+bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant,
+ const char *ExtraCode, raw_ostream &O) {
+ // Does this asm operand have a single letter operand modifier?
+ if (ExtraCode && ExtraCode[0]) {
+ if (ExtraCode[1])
+ return true; // Unknown modifier.
+
+ switch (ExtraCode[0]) {
+ // The highest-numbered register of a pair.
+ case 'H': {
+ if (OpNo == 0)
+ return true;
+ const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);
+ if (!FlagsOP.isImm())
+ return true;
+ unsigned Flags = FlagsOP.getImm();
+ unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
+ if (NumVals != 2)
+ return true;
+ unsigned RegOp = OpNo + 1;
+ if (RegOp >= MI->getNumOperands())
+ return true;
+ const MachineOperand &MO = MI->getOperand(RegOp);
+ if (!MO.isReg())
+ return true;
+ unsigned Reg = MO.getReg();
+ O << LanaiInstPrinter::getRegisterName(Reg);
+ return false;
+ }
+ default:
+ return true; // Unknown modifier.
+ }
+ }
+ printOperand(MI, OpNo, O);
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+void LanaiAsmPrinter::emitCallInstruction(const MachineInstr *MI) {
+ assert((MI->getOpcode() == Lanai::CALL || MI->getOpcode() == Lanai::CALLR) &&
+ "Unsupported call function");
+
+ LanaiMCInstLower MCInstLowering(OutContext, *Mang, *this);
+ MCSubtargetInfo STI = getSubtargetInfo();
+ // Insert save rca instruction immediately before the call.
+ // TODO: We should generate a pc-relative mov instruction here instead
+ // of pc + 16 (should be mov .+16 %rca).
+ OutStreamer->EmitInstruction(MCInstBuilder(Lanai::ADD_I_LO)
+ .addReg(Lanai::RCA)
+ .addReg(Lanai::PC)
+ .addImm(16),
+ STI);
+
+ // Push rca onto the stack.
+ // st %rca, [--%sp]
+ OutStreamer->EmitInstruction(MCInstBuilder(Lanai::SW_RI)
+ .addReg(Lanai::RCA)
+ .addReg(Lanai::SP)
+ .addImm(-4)
+ .addImm(LPAC::makePreOp(LPAC::ADD)),
+ STI);
+
+ // Lower the call instruction.
+ if (MI->getOpcode() == Lanai::CALL) {
+ MCInst TmpInst;
+ MCInstLowering.Lower(MI, TmpInst);
+ TmpInst.setOpcode(Lanai::BT);
+ OutStreamer->EmitInstruction(TmpInst, STI);
+ } else {
+ OutStreamer->EmitInstruction(MCInstBuilder(Lanai::ADD_R)
+ .addReg(Lanai::PC)
+ .addReg(MI->getOperand(0).getReg())
+ .addReg(Lanai::R0)
+ .addImm(LPCC::ICC_T),
+ STI);
+ }
+}
+
+void LanaiAsmPrinter::customEmitInstruction(const MachineInstr *MI) {
+ LanaiMCInstLower MCInstLowering(OutContext, *Mang, *this);
+ MCSubtargetInfo STI = getSubtargetInfo();
+ MCInst TmpInst;
+ MCInstLowering.Lower(MI, TmpInst);
+ OutStreamer->EmitInstruction(TmpInst, STI);
+}
+
+void LanaiAsmPrinter::EmitInstruction(const MachineInstr *MI) {
+ MachineBasicBlock::const_instr_iterator I = MI->getIterator();
+ MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
+
+ do {
+ if (I->isCall()) {
+ emitCallInstruction(&*I);
+ continue;
+ }
+
+ customEmitInstruction(&*I);
+ } while ((++I != E) && I->isInsideBundle());
+}
+
+// isBlockOnlyReachableByFallthough - Return true if the basic block has
+// exactly one predecessor and the control transfer mechanism between
+// the predecessor and this block is a fall-through.
+// FIXME: could the overridden cases be handled in AnalyzeBranch?
+bool LanaiAsmPrinter::isBlockOnlyReachableByFallthrough(
+ const MachineBasicBlock *MBB) const {
+ // The predecessor has to be immediately before this block.
+ const MachineBasicBlock *Pred = *MBB->pred_begin();
+
+ // If the predecessor is a switch statement, assume a jump table
+ // implementation, so it is not a fall through.
+ if (const BasicBlock *B = Pred->getBasicBlock())
+ if (isa<SwitchInst>(B->getTerminator()))
+ return false;
+
+ // Check default implementation
+ if (!AsmPrinter::isBlockOnlyReachableByFallthrough(MBB))
+ return false;
+
+ // Otherwise, check the last instruction.
+ // Check if the last terminator is an unconditional branch.
+ MachineBasicBlock::const_iterator I = Pred->end();
+ while (I != Pred->begin() && !(--I)->isTerminator()) {
+ }
+
+ return !I->isBarrier();
+}
+
+// Force static initialization.
+extern "C" void LLVMInitializeLanaiAsmPrinter() {
+ RegisterAsmPrinter<LanaiAsmPrinter> X(TheLanaiTarget);
+}
diff --git a/lib/Target/Lanai/LanaiCallingConv.td b/lib/Target/Lanai/LanaiCallingConv.td
new file mode 100644
index 00000000000..056b329c33c
--- /dev/null
+++ b/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<i32>>,
+
+ // Put argument in registers if marked 'inreg' and not a vararg call.
+ CCIfNotVarArg<CCIfInReg<CCIfType<[i32],
+ CCAssignToReg<[R6, R7, R18, R19]>>>>,
+
+ // Otherwise they are assigned to the stack in 4-byte aligned units.
+ CCAssignToStack<4, 4>
+]>;
+
+// Lanai 32-bit Fast Calling convention.
+def CC_Lanai32_Fast : CallingConv<[
+ // Promote i8/i16 args to i32
+ CCIfType<[ i8, i16 ], CCPromoteToType<i32>>,
+
+ // Put arguments in registers.
+ CCIfNotVarArg<CCIfType<[i32], CCAssignToReg<[ R6, R7, R18, R19 ]>>>,
+
+ // Otherwise they are assigned to the stack in 4-byte aligned units.
+ CCAssignToStack<4, 4>
+]>;
+
+// Lanai 32-bit C return-value convention.
+def RetCC_Lanai32 : CallingConv<[
+ // Specify two registers to allow returning 64-bit results that have already
+ // been lowered to 2 32-bit values.
+ CCIfType<[i32], CCAssignToReg<[RV, R9]>>
+]>;
+
+def CSR: CalleeSavedRegs<(add)>;
diff --git a/lib/Target/Lanai/LanaiCondCode.h b/lib/Target/Lanai/LanaiCondCode.h
new file mode 100644
index 00000000000..6c5bdefc83d
--- /dev/null
+++ b/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<CondCode>(S)
+ .EndsWith("f", LPCC::ICC_F)
+ .EndsWith("hi", LPCC::ICC_HI)
+ .EndsWith("ugt", LPCC::ICC_UGT)
+ .EndsWith("ls", LPCC::ICC_LS)
+ .EndsWith("ule", LPCC::ICC_ULE)
+ .EndsWith("cc", LPCC::ICC_CC)
+ .EndsWith("ult", LPCC::ICC_ULT)
+ .EndsWith("cs", LPCC::ICC_CS)
+ .EndsWith("uge", LPCC::ICC_UGE)
+ .EndsWith("ne", LPCC::ICC_NE)
+ .EndsWith("eq", LPCC::ICC_EQ)
+ .EndsWith("vc", LPCC::ICC_VC)
+ .EndsWith("vs", LPCC::ICC_VS)
+ .EndsWith("pl", LPCC::ICC_PL)
+ .EndsWith("mi", LPCC::ICC_MI)
+ .EndsWith("ge", LPCC::ICC_GE)
+ .EndsWith("lt", LPCC::ICC_LT)
+ .EndsWith("gt", LPCC::ICC_GT)
+ .EndsWith("le", LPCC::ICC_LE)
+ .EndsWith("t", LPCC::ICC_T) // Has to be after others with suffix t
+ .Default(LPCC::UNKNOWN);
+}
+} // namespace LPCC
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_LANAI_LANAICONDCODE_H
diff --git a/lib/Target/Lanai/LanaiDelaySlotFiller.cpp b/lib/Target/Lanai/LanaiDelaySlotFiller.cpp
new file mode 100644
index 00000000000..4154b9cc9c9
--- /dev/null
+++ b/lib/Target/Lanai/LanaiDelaySlotFiller.cpp
@@ -0,0 +1,250 @@
+//===-- LanaiDelaySlotFiller.cpp - Lanai delay slot filler ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple pass to fills delay slots with useful instructions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Lanai.h"
+#include "LanaiTargetMachine.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Target/TargetInstrInfo.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "delay-slot-filler"
+
+STATISTIC(FilledSlots, "Number of delay slots filled");
+
+static cl::opt<bool>
+ NopDelaySlotFiller("lanai-nop-delay-filler", cl::init(false),
+ cl::desc("Fill Lanai delay slots with NOPs."),
+ cl::Hidden);
+
+namespace {
+struct Filler : public MachineFunctionPass {
+ // Target machine description which we query for reg. names, data
+ // layout, etc.
+ const TargetInstrInfo *TII;
+ const TargetRegisterInfo *TRI;
+ MachineBasicBlock::instr_iterator LastFiller;
+
+ static char ID;
+ explicit Filler() : MachineFunctionPass(ID) {}
+
+ const char *getPassName() const override { return "Lanai Delay Slot Filler"; }
+
+ bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
+
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ const LanaiSubtarget &Subtarget = MF.getSubtarget<LanaiSubtarget>();
+ TII = Subtarget.getInstrInfo();
+ TRI = Subtarget.getRegisterInfo();
+
+ bool Changed = false;
+ for (MachineFunction::iterator FI = MF.begin(), FE = MF.end(); FI != FE;
+ ++FI)
+ Changed |= runOnMachineBasicBlock(*FI);
+ return Changed;
+ }
+
+ void insertDefsUses(MachineBasicBlock::instr_iterator MI,
+ SmallSet<unsigned, 32> &RegDefs,
+ SmallSet<unsigned, 32> &RegUses);
+
+ bool isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg);
+
+ bool delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,
+ bool &SawStore, SmallSet<unsigned, 32> &RegDefs,
+ SmallSet<unsigned, 32> &RegUses);
+
+ bool findDelayInstr(MachineBasicBlock &MBB,
+ MachineBasicBlock::instr_iterator Slot,
+ MachineBasicBlock::instr_iterator &Filler);
+};
+char Filler::ID = 0;
+} // end of anonymous namespace
+
+// createLanaiDelaySlotFillerPass - Returns a pass that fills in delay
+// slots in Lanai MachineFunctions
+FunctionPass *
+llvm::createLanaiDelaySlotFillerPass(const LanaiTargetMachine &tm) {
+ return new Filler();
+}
+
+// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
+// There is one or two delay slot per delayed instruction.
+bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
+ bool Changed = false;
+ LastFiller = MBB.instr_end();
+
+ for (MachineBasicBlock::instr_iterator I = MBB.instr_begin();
+ I != MBB.instr_end(); ++I) {
+ if (I->getDesc().hasDelaySlot()) {
+ MachineBasicBlock::instr_iterator InstrWithSlot = I;
+ MachineBasicBlock::instr_iterator J = I;
+
+ // Treat RET specially as it is only instruction with 2 delay slots
+ // generated while all others generated have 1 delay slot.
+ if (I->getOpcode() == Lanai::RET) {
+ // RET is generated as part of epilogue generation and hence we know
+ // what the two instructions preceding it are and that it is safe to
+ // insert RET above them.
+ MachineBasicBlock::reverse_instr_iterator RI(I);
+ assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() &&
+ RI->getOperand(0).getReg() == Lanai::FP &&
+ RI->getOperand(1).isReg() &&
+ RI->getOperand(1).getReg() == Lanai::FP &&
+ RI->getOperand(2).isImm() && RI->getOperand(2).getImm() == -8);
+ ++RI;
+ assert(RI->getOpcode() == Lanai::ADD_I_LO &&
+ RI->getOperand(0).isReg() &&
+ RI->getOperand(0).getReg() == Lanai::SP &&
+ RI->getOperand(1).isReg() &&
+ RI->getOperand(1).getReg() == Lanai::FP);
+ ++RI;
+ MachineBasicBlock::instr_iterator FI(RI.base());
+ MBB.splice(std::next(I), &MBB, FI, I);
+ FilledSlots += 2;
+ } else {
+ if (!NopDelaySlotFiller && findDelayInstr(MBB, I, J)) {
+ MBB.splice(std::next(I), &MBB, J);
+ } else {
+ BuildMI(MBB, std::next(I), DebugLoc(), TII->get(Lanai::NOP));
+ }
+ ++FilledSlots;
+ }
+
+ Changed = true;
+ // Record the filler instruction that filled the delay slot.
+ // The instruction after it will be visited in the next iteration.
+ LastFiller = ++I;
+
+ // Bundle the delay slot filler to InstrWithSlot so that the machine
+ // verifier doesn't expect this instruction to be a terminator.
+ MIBundleBuilder(MBB, InstrWithSlot, std::next(LastFiller));
+ }
+ }
+ return Changed;
+}
+
+bool Filler::findDelayInstr(MachineBasicBlock &MBB,
+ MachineBasicBlock::instr_iterator Slot,
+ MachineBasicBlock::instr_iterator &Filler) {
+ SmallSet<unsigned, 32> RegDefs;
+ SmallSet<unsigned, 32> RegUses;
+
+ insertDefsUses(Slot, RegDefs, RegUses);
+
+ bool SawLoad = false;
+ bool SawStore = false;
+
+ for (MachineBasicBlock::reverse_instr_iterator I(Slot); I != MBB.instr_rend();
+ ++I) {
+ // skip debug value
+ if (I->isDebugValue())
+ continue;
+
+ // Convert to forward iterator.
+ MachineBasicBlock::instr_iterator FI(std::next(I).base());
+
+ if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() ||
+ FI == LastFiller || I->isPseudo())
+ break;
+
+ if (delayHasHazard(FI, SawLoad, SawStore, RegDefs, RegUses)) {
+ insertDefsUses(FI, RegDefs, RegUses);
+ continue;
+ }
+ Filler = FI;
+ return true;
+ }
+ return false;
+}
+
+bool Filler::delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,
+ bool &SawStore, SmallSet<unsigned, 32> &RegDefs,
+ SmallSet<unsigned, 32> &RegUses) {
+ if (MI->isImplicitDef() || MI->isKill())
+ return true;
+
+ // Loads or stores cannot be moved past a store to the delay slot
+ // and stores cannot be moved past a load.
+ if (MI->mayLoad()) {
+ if (SawStore)
+ return true;
+ SawLoad = true;
+ }
+
+ if (MI->mayStore()) {
+ if (SawStore)
+ return true;
+ SawStore = true;
+ if (SawLoad)
+ return true;
+ }
+
+ assert((!MI->isCall() && !MI->isReturn()) &&
+ "Cannot put calls or returns in delay slot.");
+
+ for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
+ const MachineOperand &MO = MI->getOperand(I);
+ unsigned Reg;
+
+ if (!MO.isReg() || !(Reg = MO.getReg()))
+ continue; // skip
+
+ if (MO.isDef()) {
+ // check whether Reg is defined or used before delay slot.
+ if (isRegInSet(RegDefs, Reg) || isRegInSet(RegUses, Reg))
+ return true;
+ }
+ if (MO.isUse()) {
+ // check whether Reg is defined before delay slot.
+ if (isRegInSet(RegDefs, Reg))
+ return true;
+ }
+ }
+ return false;
+}
+
+// Insert Defs and Uses of MI into the sets RegDefs and RegUses.
+void Filler::insertDefsUses(MachineBasicBlock::instr_iterator MI,
+ SmallSet<unsigned, 32> &RegDefs,
+ SmallSet<unsigned, 32> &RegUses) {
+ // If MI is a call or return, just examine the explicit non-variadic operands.
+ MCInstrDesc MCID = MI->getDesc();
+ unsigned E = MI->isCall() || MI->isReturn() ? MCID.getNumOperands()
+ : MI->getNumOperands();
+ for (unsigned I = 0; I != E; ++I) {
+ const MachineOperand &MO = MI->getOperand(I);
+ unsigned Reg;
+
+ if (!MO.isReg() || !(Reg = MO.getReg()))
+ continue;
+
+ if (MO.isDef())
+ RegDefs.insert(Reg);
+ else if (MO.isUse())
+ RegUses.insert(Reg);
+ }
+}
+
+// Returns true if the Reg or its alias is in the RegSet.
+bool Filler::isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg) {
+ // Check Reg and all aliased Registers.
+ for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
+ if (RegSet.count(*AI))
+ return true;
+ return false;
+}
diff --git a/lib/Target/Lanai/LanaiFrameLowering.cpp b/lib/Target/Lanai/LanaiFrameLowering.cpp
new file mode 100644
index 00000000000..da54f6e75c4
--- /dev/null
+++ b/lib/Target/Lanai/LanaiFrameLowering.cpp
@@ -0,0 +1,220 @@
+//===-- LanaiFrameLowering.cpp - Lanai Frame Information ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Lanai implementation of TargetFrameLowering class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LanaiFrameLowering.h"
+
+#include "LanaiInstrInfo.h"
+#include "LanaiMachineFunctionInfo.h"
+#include "LanaiSubtarget.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Function.h"
+
+using namespace llvm;
+
+// Determines the size of the frame and maximum call frame size.
+void LanaiFrameLowering::determineFrameLayout(MachineFunction &MF) const {
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ const LanaiRegisterInfo *LRI = STI.getRegisterInfo();
+
+ // Get the number of bytes to allocate from the FrameInfo.
+ unsigned FrameSize = MFI->getStackSize();
+
+ // Get the alignment.
+ unsigned StackAlign = LRI->needsStackRealignment(MF) ? MFI->getMaxAlignment()
+ : getStackAlignment();
+
+ // Get the maximum call frame size of all the calls.
+ unsigned MaxCallFrameSize = MFI->getMaxCallFrameSize();
+
+ // If we have dynamic alloca then MaxCallFrameSize needs to be aligned so
+ // that allocations will be aligned.
+ if (MFI->hasVarSizedObjects())
+ MaxCallFrameSize = alignTo(MaxCallFrameSize, StackAlign);
+
+ // Update maximum call frame size.
+ MFI->setMaxCallFrameSize(MaxCallFrameSize);
+
+ // Include call frame size in total.
+ if (!(hasReservedCallFrame(MF) && MFI->adjustsStack()))
+ FrameSize += MaxCallFrameSize;
+
+ // Make sure the frame is aligned.
+ FrameSize = alignTo(FrameSize, StackAlign);
+
+ // Update frame info.
+ MFI->setStackSize(FrameSize);
+}
+
+// Iterates through each basic block in a machine function and replaces
+// ADJDYNALLOC pseudo instructions with a Lanai:ADDI with the
+// maximum call frame size as the immediate.
+void LanaiFrameLowering::replaceAdjDynAllocPseudo(MachineFunction &MF) const {
+ const LanaiInstrInfo &LII =
+ *static_cast<const LanaiInstrInfo *>(STI.getInstrInfo());
+ unsigned MaxCallFrameSize = MF.getFrameInfo()->getMaxCallFrameSize();
+
+ for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); MBB != E;
+ ++MBB) {
+ MachineBasicBlock::iterator MBBI = MBB->begin();
+ while (MBBI != MBB->end()) {
+ MachineInstr *MI = MBBI++;
+ if (MI->getOpcode() == Lanai::ADJDYNALLOC) {
+ DebugLoc DL = MI->getDebugLoc();
+ unsigned Dst = MI->getOperand(0).getReg();
+ unsigned Src = MI->getOperand(1).getReg();
+
+ BuildMI(*MBB, MI, DL, LII.get(Lanai::ADD_I_LO), Dst)
+ .addReg(Src)
+ .addImm(MaxCallFrameSize);
+ MI->eraseFromParent();
+ }
+ }
+ }
+}
+
+// Generates the following sequence for function entry:
+// st %fp,-4[*%sp] !push old FP
+// add %sp,8,%fp !generate new FP
+// sub %sp,0x4,%sp !allocate stack space (as needed)
+void LanaiFrameLowering::emitPrologue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
+
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ const LanaiInstrInfo &LII =
+ *static_cast<const LanaiInstrInfo *>(STI.getInstrInfo());
+ MachineBasicBlock::iterator MBBI = MBB.begin();
+
+ // Debug location must be unknown since the first debug location is used
+ // to determine the end of the prologue.
+ DebugLoc DL;
+
+ // Determine the correct frame layout
+ determineFrameLayout(MF);
+
+ // FIXME: This appears to be overallocating. Needs investigation.
+ // Get the number of bytes to allocate from the FrameInfo.
+ unsigned StackSize = MFI->getStackSize();
+
+ // Push old FP
+ // st %fp,-4[*%sp]
+ BuildMI(MBB, MBBI, DL, LII.get(Lanai::SW_RI))
+ .addReg(Lanai::FP)
+ .addReg(Lanai::SP)
+ .addImm(-4)
+ .addImm(LPAC::makePreOp(LPAC::ADD))
+ .setMIFlag(MachineInstr::FrameSetup);
+
+ // Generate new FP
+ // add %sp,8,%fp
+ BuildMI(MBB, MBBI, DL, LII.get(Lanai::ADD_I_LO), Lanai::FP)
+ .addReg(Lanai::SP)
+ .addImm(8)
+ .setMIFlag(MachineInstr::FrameSetup);
+
+ // Allocate space on the stack if needed
+ // sub %sp,StackSize,%sp
+ if (StackSize != 0) {
+ BuildMI(MBB, MBBI, DL, LII.get(Lanai::SUB_I_LO), Lanai::SP)
+ .addReg(Lanai::SP)
+ .addImm(StackSize)
+ .setMIFlag(MachineInstr::FrameSetup);
+ }
+
+ // Replace ADJDYNANALLOC
+ if (MFI->hasVarSizedObjects())
+ replaceAdjDynAllocPseudo(MF);
+}
+
+void LanaiFrameLowering::eliminateCallFramePseudoInstr(
+ MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I) const {
+ // Discard ADJCALLSTACKDOWN, ADJCALLSTACKUP instructions.
+ MBB.erase(I);
+}
+
+// The function epilogue should not depend on the current stack pointer!
+// It should use the frame pointer only. This is mandatory because
+// of alloca; we also take advantage of it to omit stack adjustments
+// before returning.
+//
+// Note that when we go to restore the preserved register values we must
+// not try to address their slots by using offsets from the stack pointer.
+// That's because the stack pointer may have been moved during the function
+// execution due to a call to alloca(). Rather, we must restore all
+// preserved registers via offsets from the frame pointer value.
+//
+// Note also that when the current frame is being "popped" (by adjusting
+// the value of the stack pointer) on function exit, we must (for the
+// sake of alloca) set the new value of the stack pointer based upon
+// the current value of the frame pointer. We can't just add what we
+// believe to be the (static) frame size to the stack pointer because
+// if we did that, and alloca() had been called during this function,
+// we would end up returning *without* having fully deallocated all of
+// the space grabbed by alloca. If that happened, and a function
+// containing one or more alloca() calls was called over and over again,
+// then the stack would grow without limit!
+//
+// RET is lowered to
+// ld -4[%fp],%pc # modify %pc (two delay slots)
+// as the return address is in the stack frame and mov to pc is allowed.
+// emitEpilogue emits
+// mov %fp,%sp # restore the stack pointer
+// ld -8[%fp],%fp # restore the caller's frame pointer
+// before RET and the delay slot filler will move RET such that these
+// instructions execute in the delay slots of the load to PC.
+void LanaiFrameLowering::emitEpilogue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
+ const LanaiInstrInfo &LII =
+ *static_cast<const LanaiInstrInfo *>(STI.getInstrInfo());
+ DebugLoc DL = MBBI->getDebugLoc();
+
+ // Restore the stack pointer using the callee's frame pointer value.
+ BuildMI(MBB, MBBI, DL, LII.get(Lanai::ADD_I_LO), Lanai::SP)
+ .addReg(Lanai::FP)
+ .addImm(0);
+
+ // Restore the frame pointer from the stack.
+ BuildMI(MBB, MBBI, DL, LII.get(Lanai::LDW_RI), Lanai::FP)
+ .addReg(Lanai::FP)
+ .addImm(-8)
+ .addImm(LPAC::ADD);
+}
+
+void LanaiFrameLowering::determineCalleeSaves(MachineFunction &MF,
+ BitVector &SavedRegs,
+ RegScavenger *RS) const {
+ TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
+
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ const LanaiRegisterInfo *LRI =
+ static_cast<const LanaiRegisterInfo *>(STI.getRegisterInfo());
+ int Offset = -4;
+
+ // Reserve 4 bytes for the saved RCA
+ MFI->CreateFixedObject(4, Offset, true);
+ Offset -= 4;
+
+ // Reserve 4 bytes for the saved FP
+ MFI->CreateFixedObject(4, Offset, true);
+ Offset -= 4;
+
+ if (LRI->hasBasePointer(MF)) {
+ MFI->CreateFixedObject(4, Offset, true);
+ SavedRegs.reset(LRI->getBaseRegister());
+ }
+}
diff --git a/lib/Target/Lanai/LanaiFrameLowering.h b/lib/Target/Lanai/LanaiFrameLowering.h
new file mode 100644
index 00000000000..2027da9e35a
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/LanaiISelDAGToDAG.cpp b/lib/Target/Lanai/LanaiISelDAGToDAG.cpp
new file mode 100644
index 00000000000..01d5b39e9a3
--- /dev/null
+++ b/lib/Target/Lanai/LanaiISelDAGToDAG.cpp
@@ -0,0 +1,325 @@
+//===-- LanaiISelDAGToDAG.cpp - A dag to dag inst selector for Lanai ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines an instruction selector for the Lanai target.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Lanai.h"
+#include "LanaiMachineFunctionInfo.h"
+#include "LanaiRegisterInfo.h"
+#include "LanaiSubtarget.h"
+#include "LanaiTargetMachine.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "lanai-isel"
+
+//===----------------------------------------------------------------------===//
+// Instruction Selector Implementation
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// LanaiDAGToDAGISel - Lanai specific code to select Lanai machine
+// instructions for SelectionDAG operations.
+//===----------------------------------------------------------------------===//
+namespace {
+
+class LanaiDAGToDAGISel : public SelectionDAGISel {
+public:
+ explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine)
+ : SelectionDAGISel(TargetMachine) {}
+
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ return SelectionDAGISel::runOnMachineFunction(MF);
+ }
+
+ // Pass Name
+ const char *getPassName() const override {
+ return "Lanai DAG->DAG Pattern Instruction Selection";
+ }
+
+ bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
+ std::vector<SDValue> &OutOps) override;
+
+private:
+// Include the pieces autogenerated from the target description.
+#include "LanaiGenDAGISel.inc"
+
+ // Instruction Selection not handled by the auto-generated tablgen
+ SDNode *Select(SDNode *N) override;
+
+ // Support functions for the opcodes of Instruction Selection
+ // not handled by the auto-generated tablgen
+ SDNode *selectFrameIndex(SDNode *N);
+
+ // Complex Pattern for address selection.
+ bool selectAddrRi(SDValue Addr, SDValue &Base, SDValue &Offset,
+ SDValue &AluOp);
+ bool selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2, SDValue &AluOp);
+ bool selectAddrSls(SDValue Addr, SDValue &Offset);
+ bool selectAddrSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
+ SDValue &AluOp);
+
+ // getI32Imm - Return a target constant with the specified value, of type i32.
+ inline SDValue getI32Imm(unsigned Imm, SDLoc DL) {
+ return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
+ }
+
+private:
+ bool selectAddrRiSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
+ SDValue &AluOp, bool RiMode);
+};
+
+bool canBeRepresentedAsSls(const ConstantSDNode &CN) {
+ // Fits in 21-bit signed immediate and two low-order bits are zero.
+ return isInt<21>(CN.getSExtValue()) && ((CN.getSExtValue() & 0x3) == 0);
+}
+
+} // namespace
+
+// Helper functions for ComplexPattern used on LanaiInstrInfo
+// Used on Lanai Load/Store instructions.
+bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr, SDValue &Offset) {
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
+ SDLoc DL(Addr);
+ // Loading from a constant address.
+ if (canBeRepresentedAsSls(*CN)) {
+ int32_t Imm = CN->getSExtValue();
+ Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
+ return true;
+ }
+ }
+ if (Addr.getOpcode() == ISD::OR &&
+ Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) {
+ Offset = Addr.getOperand(1).getOperand(0);
+ return true;
+ }
+ return false;
+}
+
+bool LanaiDAGToDAGISel::selectAddrRiSpls(SDValue Addr, SDValue &Base,
+ SDValue &Offset, SDValue &AluOp,
+ bool RiMode) {
+ SDLoc DL(Addr);
+
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
+ if (RiMode) {
+ // Fits in 16-bit signed immediate.
+ if (isInt<16>(CN->getSExtValue())) {
+ int16_t Imm = CN->getSExtValue();
+ Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
+ Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
+ AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
+ return true;
+ }
+ // Allow SLS to match if the constant doesn't fit in 16 bits but can be
+ // represented as an SLS.
+ if (canBeRepresentedAsSls(*CN))
+ return false;
+ } else {
+ // Fits in 10-bit signed immediate.
+ if (isInt<10>(CN->getSExtValue())) {
+ int16_t Imm = CN->getSExtValue();
+ Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
+ Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
+ AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
+ return true;
+ }
+ }
+ }
+
+ // if Address is FI, get the TargetFrameIndex.
+ if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
+ Base = CurDAG->getTargetFrameIndex(
+ FIN->getIndex(),
+ getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
+ Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
+ AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
+ return true;
+ }
+
+ // Skip direct calls
+ if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
+ Addr.getOpcode() == ISD::TargetGlobalAddress))
+ return false;
+
+ // Address of the form imm + reg
+ ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode());
+ if (AluOperator == ISD::ADD) {
+ AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
+ // Addresses of the form FI+const
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
+ if ((RiMode && isInt<16>(CN->getSExtValue())) ||
+ (!RiMode && isInt<10>(CN->getSExtValue()))) {
+ // If the first operand is a FI, get the TargetFI Node
+ if (FrameIndexSDNode *FIN =
+ dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
+ Base = CurDAG->getTargetFrameIndex(
+ FIN->getIndex(),
+ getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
+ } else {
+ Base = Addr.getOperand(0);
+ }
+
+ Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i32);
+ return true;
+ }
+ }
+
+ // Let SLS match SMALL instead of RI.
+ if (AluOperator == ISD::OR && RiMode &&
+ Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
+ return false;
+
+ Base = Addr;
+ Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
+ AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
+ return true;
+}
+
+bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr, SDValue &Base,
+ SDValue &Offset, SDValue &AluOp) {
+ return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RImode=*/true);
+}
+
+bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr, SDValue &Base,
+ SDValue &Offset, SDValue &AluOp) {
+ return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/false);
+}
+
+bool LanaiDAGToDAGISel::selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2,
+ SDValue &AluOp) {
+ // if Address is FI, get the TargetFrameIndex.
+ if (Addr.getOpcode() == ISD::FrameIndex)
+ return false;
+
+ // Skip direct calls
+ if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
+ Addr.getOpcode() == ISD::TargetGlobalAddress))
+ return false;
+
+ // Address of the form OP + OP
+ ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode());
+ LPAC::AluCode AluCode = LPAC::isdToLanaiAluCode(AluOperator);
+ if (AluCode != LPAC::UNKNOWN) {
+ // Skip addresses of the form FI OP const
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
+ if (isInt<16>(CN->getSExtValue()))
+ return false;
+
+ // Skip addresses with hi/lo operands
+ if (Addr.getOperand(0).getOpcode() == LanaiISD::HI ||
+ Addr.getOperand(0).getOpcode() == LanaiISD::LO ||
+ Addr.getOperand(0).getOpcode() == LanaiISD::SMALL ||
+ Addr.getOperand(1).getOpcode() == LanaiISD::HI ||
+ Addr.getOperand(1).getOpcode() == LanaiISD::LO ||
+ Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
+ return false;
+
+ // Addresses of the form register OP register
+ R1 = Addr.getOperand(0);
+ R2 = Addr.getOperand(1);
+ AluOp = CurDAG->getTargetConstant(AluCode, SDLoc(Addr), MVT::i32);
+ return true;
+ }
+
+ // Skip addresses with zero offset
+ return false;
+}
+
+bool LanaiDAGToDAGISel::SelectInlineAsmMemoryOperand(
+ const SDValue &Op, unsigned ConstraintCode, std::vector<SDValue> &OutOps) {
+ SDValue Op0, Op1, AluOp;
+ switch (ConstraintCode) {
+ default:
+ return true;
+ case InlineAsm::Constraint_m: // memory
+ if (!selectAddrRr(Op, Op0, Op1, AluOp) &&
+ !selectAddrRi(Op, Op0, Op1, AluOp))
+ return true;
+ break;
+ }
+
+ OutOps.push_back(Op0);
+ OutOps.push_back(Op1);
+ OutOps.push_back(AluOp);
+ return false;
+}
+
+// Select instructions not customized! Used for
+// expanded, promoted and normal instructions
+SDNode *LanaiDAGToDAGISel::Select(SDNode *Node) {
+ unsigned Opcode = Node->getOpcode();
+
+ // Dump information about the Node being selected
+ DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n");
+
+ // If we have a custom node, we already have selected!
+ if (Node->isMachineOpcode()) {
+ DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
+ return NULL;
+ }
+
+ // Instruction Selection not handled by the auto-generated
+ // tablegen selection should be handled here.
+ SDNode *ResNode = nullptr;
+ switch (Opcode) {
+ case ISD::FrameIndex:
+ ResNode = selectFrameIndex(Node);
+ break;
+ default:
+ break;
+ }
+
+ // Select the default instruction
+ if (ResNode == nullptr)
+ ResNode = SelectCode(Node);
+
+ DEBUG(errs() << "=> ");
+ if (ResNode == NULL || ResNode == Node)
+ DEBUG(Node->dump(CurDAG));
+ else
+ DEBUG(ResNode->dump(CurDAG));
+ DEBUG(errs() << "\n");
+ return ResNode;
+}
+
+SDNode *LanaiDAGToDAGISel::selectFrameIndex(SDNode *Node) {
+ SDLoc DL(Node);
+ SDValue Imm = CurDAG->getTargetConstant(0, DL, MVT::i32);
+ int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex();
+ EVT VT = Node->getValueType(0);
+ SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
+ unsigned Opc = Lanai::ADD_I_LO;
+ if (Node->hasOneUse())
+ return CurDAG->SelectNodeTo(Node, Opc, VT, TFI, Imm);
+ return CurDAG->getMachineNode(Opc, DL, VT, TFI, Imm);
+}
+
+// createLanaiISelDag - This pass converts a legalized DAG into a
+// Lanai-specific DAG, ready for instruction scheduling.
+FunctionPass *llvm::createLanaiISelDag(LanaiTargetMachine &TM) {
+ return new LanaiDAGToDAGISel(TM);
+}
diff --git a/lib/Target/Lanai/LanaiISelLowering.cpp b/lib/Target/Lanai/LanaiISelLowering.cpp
new file mode 100644
index 00000000000..b18e04dc6a0
--- /dev/null
+++ b/lib/Target/Lanai/LanaiISelLowering.cpp
@@ -0,0 +1,1207 @@
+//===-- 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<int> 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(const TargetMachine &TM,
+ const LanaiSubtarget &STI)
+ : TargetLowering(TM) {
+ // Set up the register classes.
+ addRegisterClass(MVT::i32, &Lanai::GPRRegClass);
+
+ // Compute derived properties from the register classes
+ TRI = STI.getRegisterInfo();
+ computeRegisterProperties(TRI);
+
+ 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<RTLIB::Libcall>(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<unsigned>(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<unsigned, const TargetRegisterClass *>
+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<ConstantInt>(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<SDValue> &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<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &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<SDValue> &InVals) const {
+ SelectionDAG &DAG = CLI.DAG;
+ SDLoc &DL = CLI.DL;
+ SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
+ SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
+ SmallVectorImpl<ISD::InputArg> &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<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineRegisterInfo &RegInfo = MF.getRegInfo();
+ LanaiMachineFunctionInfo *LanaiMFI = MF.getInfo<LanaiMachineFunctionInfo>();
+
+ // Assign locations to all of the incoming arguments.
+ SmallVector<CCValAssign, 16> 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<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ SDLoc DL, SelectionDAG &DAG) const {
+ // CCValAssign - represent the assignment of the return value to a location
+ SmallVector<CCValAssign, 16> 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<SDValue, 4> 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<LanaiMachineFunctionInfo>();
+ 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<SDValue>(&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<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const {
+ // Analyze operands of the call, assigning locations to each operand.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+ GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee);
+ MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+
+ NumFixedArgs = 0;
+ if (IsVarArg && G) {
+ const Function *CalleeFn = dyn_cast<Function>(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<SDValue, 8> 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<std::pair<unsigned, SDValue>, 4> RegsToPass;
+ SmallVector<SDValue, 12> 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<SDValue>(&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<ExternalSymbolSDNode>(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<SDValue, 8> 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 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<SDValue>(&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<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const {
+ // Assign locations to each value returned by this call.
+ SmallVector<CCValAssign, 16> 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<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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<ConstantSDNode>(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<CondCodeSDNode>(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<ConstantSDNode>(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<<i as a
+ // term NAF).
+ if (HighestOne == -1)
+ Res = DAG.getConstant(0, DL, MVT::i32);
+ else {
+ Res = DAG.getNode(ISD::SHL, DL, VT, V,
+ DAG.getConstant(HighestOne, DL, MVT::i32));
+ SignedDigit[HighestOne] = 0;
+ }
+
+ // Assemble multiplication from shift, add, sub using NAF form and running
+ // sum.
+ for (unsigned int I = 0; I < sizeof(SignedDigit) / sizeof(SignedDigit[0]);
+ ++I) {
+ if (SignedDigit[I] == 0)
+ continue;
+
+ // Shifted multiplicand (v<<i).
+ SDValue Op =
+ DAG.getNode(ISD::SHL, DL, VT, V, DAG.getConstant(I, DL, MVT::i32));
+ if (SignedDigit[I] == 1)
+ Res = DAG.getNode(ISD::ADD, DL, VT, Res, Op);
+ else if (SignedDigit[I] == -1)
+ Res = DAG.getNode(ISD::SUB, DL, VT, Res, Op);
+ }
+ return Res;
+}
+
+SDValue LanaiTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
+ SDValue LHS = Op.getOperand(0);
+ SDValue RHS = Op.getOperand(1);
+ ISD::CondCode CC = cast<CondCodeSDNode>(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<CondCodeSDNode>(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<LanaiMachineFunctionInfo>();
+
+ 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<SrcValueSDNode>(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 {
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ MFI->setReturnAddressIsTaken(true);
+
+ EVT VT = Op.getValueType();
+ SDLoc DL(Op);
+ unsigned Depth = cast<ConstantSDNode>(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<ConstantSDNode>(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<ConstantPoolSDNode>(Op);
+ const Constant *C = N->getConstVal();
+ const LanaiTargetObjectFile *TLOF =
+ static_cast<const LanaiTargetObjectFile *>(
+ 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)) {
+ 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<GlobalAddressSDNode>(Op)->getGlobal();
+ int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset();
+
+ const LanaiTargetObjectFile *TLOF =
+ static_cast<const LanaiTargetObjectFile *>(
+ 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<BlockAddressSDNode>(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<JumpTableSDNode>(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;
+ }
+}
diff --git a/lib/Target/Lanai/LanaiISelLowering.h b/lib/Target/Lanai/LanaiISelLowering.h
new file mode 100644
index 00000000000..57623d05ae2
--- /dev/null
+++ b/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 "LanaiRegisterInfo.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/Target/TargetLowering.h"
+
+namespace llvm {
+namespace LanaiISD {
+enum {
+ FIRST_NUMBER = ISD::BUILTIN_OP_END,
+
+ ADJDYNALLOC,
+
+ // Return with a flag operand. Operand 0 is the chain operand.
+ RET_FLAG,
+
+ // CALL - These operations represent an abstract call instruction, which
+ // includes a bunch of information.
+ CALL,
+
+ // SELECT_CC - Operand 0 and operand 1 are selection variable, operand 3
+ // is condition code and operand 4 is flag operand.
+ SELECT_CC,
+
+ // SETCC - Store the conditional to a register
+ SETCC,
+
+ // SET_FLAG - Set flag compare
+ SET_FLAG,
+
+ // BR_CC - Used to glue together a conditional branch and comparison
+ BR_CC,
+
+ // Wrapper - A wrapper node for TargetConstantPool, TargetExternalSymbol,
+ // and TargetGlobalAddress.
+ Wrapper,
+
+ // Get the Higher/Lower 16 bits from a 32-bit immediate
+ HI,
+ LO,
+
+ // Small 21-bit immediate in global memory
+ SMALL
+};
+} // namespace LanaiISD
+
+class LanaiSubtarget;
+
+class LanaiTargetLowering : public TargetLowering {
+public:
+ LanaiTargetLowering(const TargetMachine &TM, const LanaiSubtarget &STI);
+
+ // LowerOperation - Provide custom lowering hooks for some operations.
+ SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
+
+ // getTargetNodeName - This method returns the name of a target specific
+ // DAG node.
+ const char *getTargetNodeName(unsigned Opcode) const override;
+
+ SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerCTTZ(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerCTLZ(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerCTTZ_ZERO_UNDEF(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
+
+ unsigned getRegisterByName(const char *RegName, EVT VT,
+ SelectionDAG &DAG) const override;
+ std::pair<unsigned, const TargetRegisterClass *>
+ getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
+ StringRef Constraint, MVT VT) const override;
+ ConstraintWeight
+ getSingleConstraintMatchWeight(AsmOperandInfo &Info,
+ const char *Constraint) const override;
+ void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint,
+ std::vector<SDValue> &Ops,
+ SelectionDAG &DAG) const override;
+
+private:
+ SDValue LowerCCCCallTo(SDValue Chain, SDValue Callee,
+ CallingConv::ID CallConv, bool IsVarArg,
+ bool IsTailCall,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl,
+ SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const;
+
+ SDValue LowerCCCArguments(SDValue Chain, CallingConv::ID CallConv,
+ bool IsVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL,
+ SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const;
+
+ SDValue LowerCallResult(SDValue Chain, SDValue InFlag,
+ CallingConv::ID CallConv, bool IsVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL,
+ SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const;
+
+ SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const override;
+
+ SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv,
+ bool IsVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins,
+ SDLoc DL, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const override;
+
+ SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
+ SelectionDAG &DAG) const override;
+
+ const LanaiRegisterInfo *TRI;
+};
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_LANAI_LANAIISELLOWERING_H
diff --git a/lib/Target/Lanai/LanaiInstrFormats.td b/lib/Target/Lanai/LanaiInstrFormats.td
new file mode 100644
index 00000000000..30289ea4ac0
--- /dev/null
+++ b/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<dag outs, dag ins, string asmstr, list<dag> 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<bits<3> op, dag outs, dag ins, string asmstr,
+ list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern>, 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<bits<3> op, dag outs, dag ins, string asmstr,
+ list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern>, 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<bit S, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern> {
+ 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<bit S, dag outs, dag ins, string asmstr,
+ list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern> {
+ 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<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern> {
+ 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<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern> {
+ 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<dag outs, dag ins, string asmstr,
+ list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern> {
+ 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<bit S, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern> {
+ 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<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern> {
+ 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<dag outs, dag ins, string asmstr,
+ list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern> {
+ 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<bits<3> op, dag outs, dag ins, string asmstr,
+ list<dag> pattern> : InstLanai<outs, ins, asmstr,
+ pattern>, 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<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstLanai<outs, ins, asmstr, pattern> {
+ let Inst{15 - 0} = 0;
+ let isPseudo = 1;
+}
diff --git a/lib/Target/Lanai/LanaiInstrInfo.cpp b/lib/Target/Lanai/LanaiInstrInfo.cpp
new file mode 100644
index 00000000000..90dce19da48
--- /dev/null
+++ b/lib/Target/Lanai/LanaiInstrInfo.cpp
@@ -0,0 +1,324 @@
+//===-- LanaiInstrInfo.cpp - Lanai Instruction Information ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Lanai implementation of the TargetInstrInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Lanai.h"
+#include "LanaiInstrInfo.h"
+#include "LanaiMachineFunctionInfo.h"
+#include "LanaiTargetMachine.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h"
+
+#define GET_INSTRINFO_CTOR_DTOR
+#include "LanaiGenInstrInfo.inc"
+
+namespace llvm {
+LanaiInstrInfo::LanaiInstrInfo()
+ : LanaiGenInstrInfo(Lanai::ADJCALLSTACKDOWN, Lanai::ADJCALLSTACKUP),
+ RegisterInfo() {}
+
+void LanaiInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator Position,
+ DebugLoc DL, unsigned DestinationRegister,
+ unsigned SourceRegister,
+ bool KillSource) const {
+ if (!Lanai::GPRRegClass.contains(DestinationRegister, SourceRegister)) {
+ llvm_unreachable("Impossible reg-to-reg copy");
+ }
+
+ BuildMI(MBB, Position, DL, get(Lanai::OR_I_LO), DestinationRegister)
+ .addReg(SourceRegister, getKillRegState(KillSource))
+ .addImm(0);
+}
+
+void LanaiInstrInfo::storeRegToStackSlot(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator Position,
+ unsigned SourceRegister, bool IsKill, int FrameIndex,
+ const TargetRegisterClass *RegisterClass,
+ const TargetRegisterInfo *RegisterInfo) const {
+ DebugLoc DL;
+ if (Position != MBB.end()) {
+ DL = Position->getDebugLoc();
+ }
+
+ if (!Lanai::GPRRegClass.hasSubClassEq(RegisterClass)) {
+ llvm_unreachable("Can't store this register to stack slot");
+ }
+ BuildMI(MBB, Position, DL, get(Lanai::SW_RI))
+ .addReg(SourceRegister, getKillRegState(IsKill))
+ .addFrameIndex(FrameIndex)
+ .addImm(0)
+ .addImm(LPAC::ADD);
+}
+
+void LanaiInstrInfo::loadRegFromStackSlot(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator Position,
+ unsigned DestinationRegister, int FrameIndex,
+ const TargetRegisterClass *RegisterClass,
+ const TargetRegisterInfo *RegisterInfo) const {
+ DebugLoc DL;
+ if (Position != MBB.end()) {
+ DL = Position->getDebugLoc();
+ }
+
+ if (!Lanai::GPRRegClass.hasSubClassEq(RegisterClass)) {
+ llvm_unreachable("Can't load this register from stack slot");
+ }
+ BuildMI(MBB, Position, DL, get(Lanai::LDW_RI), DestinationRegister)
+ .addFrameIndex(FrameIndex)
+ .addImm(0)
+ .addImm(LPAC::ADD);
+}
+
+bool LanaiInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const {
+ return false;
+}
+
+static LPCC::CondCode GetOppositeBranchCondition(LPCC::CondCode CC) {
+ switch (CC) {
+ case LPCC::ICC_T: // true
+ return LPCC::ICC_F;
+ case LPCC::ICC_F: // false
+ return LPCC::ICC_T;
+ case LPCC::ICC_HI: // high
+ return LPCC::ICC_LS;
+ case LPCC::ICC_LS: // low or same
+ return LPCC::ICC_HI;
+ case LPCC::ICC_CC: // carry cleared
+ return LPCC::ICC_CS;
+ case LPCC::ICC_CS: // carry set
+ return LPCC::ICC_CC;
+ case LPCC::ICC_NE: // not equal
+ return LPCC::ICC_EQ;
+ case LPCC::ICC_EQ: // equal
+ return LPCC::ICC_NE;
+ case LPCC::ICC_VC: // oVerflow cleared
+ return LPCC::ICC_VS;
+ case LPCC::ICC_VS: // oVerflow set
+ return LPCC::ICC_VC;
+ case LPCC::ICC_PL: // plus (note: 0 is "minus" too here)
+ return LPCC::ICC_MI;
+ case LPCC::ICC_MI: // minus
+ return LPCC::ICC_PL;
+ case LPCC::ICC_GE: // greater than or equal
+ return LPCC::ICC_LT;
+ case LPCC::ICC_LT: // less than
+ return LPCC::ICC_GE;
+ case LPCC::ICC_GT: // greater than
+ return LPCC::ICC_LE;
+ case LPCC::ICC_LE: // less than or equal
+ return LPCC::ICC_GT;
+ default:
+ llvm_unreachable("Invalid condtional code");
+ }
+}
+
+// The AnalyzeBranch function is used to examine conditional instructions and
+// remove unnecessary instructions. This method is used by BranchFolder and
+// IfConverter machine function passes to improve the CFG.
+// - TrueBlock is set to the destination if condition evaluates true (it is the
+// nullptr if the destination is the fall-through branch);
+// - FalseBlock is set to the destination if condition evaluates to false (it
+// is the nullptr if the branch is unconditional);
+// - condition is populated with machine operands needed to generate the branch
+// to insert in InsertBranch;
+// Returns: false if branch could successfully be analyzed.
+bool LanaiInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
+ MachineBasicBlock *&TrueBlock,
+ MachineBasicBlock *&FalseBlock,
+ SmallVectorImpl<MachineOperand> &Condition,
+ bool AllowModify) const {
+ // Iterator to current instruction being considered.
+ MachineBasicBlock::iterator Instruction = MBB.end();
+
+ // Start from the bottom of the block and work up, examining the
+ // terminator instructions.
+ while (Instruction != MBB.begin()) {
+ --Instruction;
+
+ // Skip over debug values.
+ if (Instruction->isDebugValue())
+ continue;
+
+ // Working from the bottom, when we see a non-terminator
+ // instruction, we're done.
+ if (!isUnpredicatedTerminator(*Instruction))
+ break;
+
+ // A terminator that isn't a branch can't easily be handled
+ // by this analysis.
+ if (!Instruction->isBranch())
+ return true;
+
+ // Handle unconditional branches.
+ if (Instruction->getOpcode() == Lanai::BT) {
+ if (!AllowModify) {
+ TrueBlock = Instruction->getOperand(0).getMBB();
+ continue;
+ }
+
+ // If the block has any instructions after a branch, delete them.
+ while (std::next(Instruction) != MBB.end()) {
+ std::next(Instruction)->eraseFromParent();
+ }
+
+ Condition.clear();
+ FalseBlock = nullptr;
+
+ // Delete the jump if it's equivalent to a fall-through.
+ if (MBB.isLayoutSuccessor(Instruction->getOperand(0).getMBB())) {
+ TrueBlock = nullptr;
+ Instruction->eraseFromParent();
+ Instruction = MBB.end();
+ continue;
+ }
+
+ // TrueBlock is used to indicate the unconditional destination.
+ TrueBlock = Instruction->getOperand(0).getMBB();
+ continue;
+ }
+
+ // Handle conditional branches
+ unsigned Opcode = Instruction->getOpcode();
+ if (Opcode != Lanai::BRCC)
+ return true; // Unknown opcode.
+
+ // Multiple conditional branches are not handled here so only proceed if
+ // there are no conditions enqueued.
+ if (Condition.empty()) {
+ LPCC::CondCode BranchCond =
+ static_cast<LPCC::CondCode>(Instruction->getOperand(1).getImm());
+
+ // TrueBlock is the target of the previously seen unconditional branch.
+ FalseBlock = TrueBlock;
+ TrueBlock = Instruction->getOperand(0).getMBB();
+ Condition.push_back(MachineOperand::CreateImm(BranchCond));
+ continue;
+ }
+
+ // Multiple conditional branches are not handled.
+ return true;
+ }
+
+ // Return false indicating branch successfully analyzed.
+ return false;
+}
+
+// ReverseBranchCondition - Reverses the branch condition of the specified
+// condition list, returning false on success and true if it cannot be
+// reversed.
+bool LanaiInstrInfo::ReverseBranchCondition(
+ SmallVectorImpl<llvm::MachineOperand> &Condition) const {
+ assert((Condition.size() == 1) &&
+ "Lanai branch conditions should have one component.");
+
+ LPCC::CondCode BranchCond =
+ static_cast<LPCC::CondCode>(Condition[0].getImm());
+ Condition[0].setImm(GetOppositeBranchCondition(BranchCond));
+ return false;
+}
+
+// Insert the branch with condition specified in condition and given targets
+// (TrueBlock and FalseBlock). This function returns the number of machine
+// instructions inserted.
+unsigned LanaiInstrInfo::InsertBranch(MachineBasicBlock &MBB,
+ MachineBasicBlock *TrueBlock,
+ MachineBasicBlock *FalseBlock,
+ ArrayRef<MachineOperand> Condition,
+ DebugLoc DL) const {
+ // Shouldn't be a fall through.
+ assert(TrueBlock && "InsertBranch must not be told to insert a fallthrough");
+
+ // If condition is empty then an unconditional branch is being inserted.
+ if (Condition.empty()) {
+ assert(!FalseBlock && "Unconditional branch with multiple successors!");
+ BuildMI(&MBB, DL, get(Lanai::BT)).addMBB(TrueBlock);
+ return 1;
+ }
+
+ // Else a conditional branch is inserted.
+ assert((Condition.size() == 1) &&
+ "Lanai branch conditions should have one component.");
+ unsigned ConditionalCode = Condition[0].getImm();
+ BuildMI(&MBB, DL, get(Lanai::BRCC)).addMBB(TrueBlock).addImm(ConditionalCode);
+
+ // If no false block, then false behavior is fall through and no branch needs
+ // to be inserted.
+ if (!FalseBlock)
+ return 1;
+
+ BuildMI(&MBB, DL, get(Lanai::BT)).addMBB(FalseBlock);
+ return 2;
+}
+
+unsigned LanaiInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
+ MachineBasicBlock::iterator Instruction = MBB.end();
+ unsigned Count = 0;
+
+ while (Instruction != MBB.begin()) {
+ --Instruction;
+ if (Instruction->isDebugValue())
+ continue;
+ if (Instruction->getOpcode() != Lanai::BT &&
+ Instruction->getOpcode() != Lanai::BRCC) {
+ break;
+ }
+
+ // Remove the branch.
+ Instruction->eraseFromParent();
+ Instruction = MBB.end();
+ ++Count;
+ }
+
+ return Count;
+}
+
+unsigned LanaiInstrInfo::isLoadFromStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const {
+ if (MI->getOpcode() == Lanai::LDW_RI)
+ if (MI->getOperand(1).isFI() && MI->getOperand(2).isImm() &&
+ MI->getOperand(2).getImm() == 0) {
+ FrameIndex = MI->getOperand(1).getIndex();
+ return MI->getOperand(0).getReg();
+ }
+ return 0;
+}
+
+unsigned LanaiInstrInfo::isLoadFromStackSlotPostFE(const MachineInstr *MI,
+ int &FrameIndex) const {
+ if (MI->getOpcode() == Lanai::LDW_RI) {
+ unsigned Reg;
+ if ((Reg = isLoadFromStackSlot(MI, FrameIndex)))
+ return Reg;
+ // Check for post-frame index elimination operations
+ const MachineMemOperand *Dummy;
+ return hasLoadFromStackSlot(MI, Dummy, FrameIndex);
+ }
+ return 0;
+}
+
+unsigned LanaiInstrInfo::isStoreToStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const {
+ if (MI->getOpcode() == Lanai::SW_RI)
+ if (MI->getOperand(0).isFI() && MI->getOperand(1).isImm() &&
+ MI->getOperand(1).getImm() == 0) {
+ FrameIndex = MI->getOperand(0).getIndex();
+ return MI->getOperand(2).getReg();
+ }
+ return 0;
+}
+} // namespace llvm
diff --git a/lib/Target/Lanai/LanaiInstrInfo.h b/lib/Target/Lanai/LanaiInstrInfo.h
new file mode 100644
index 00000000000..8ae28cb9368
--- /dev/null
+++ b/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<MachineOperand> &Condition,
+ bool AllowModify) const override;
+
+ unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+
+ bool ReverseBranchCondition(
+ SmallVectorImpl<MachineOperand> &Condition) const override;
+
+ unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TrueBlock,
+ MachineBasicBlock *FalseBlock,
+ ArrayRef<MachineOperand> Condition,
+ DebugLoc DL) const override;
+};
+
+static inline bool isSPLSOpcode(unsigned Opcode) {
+ switch (Opcode) {
+ case Lanai::LDBs_RI:
+ case Lanai::LDBz_RI:
+ case Lanai::LDHs_RI:
+ case Lanai::LDHz_RI:
+ case Lanai::STB_RI:
+ case Lanai::STH_RI:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool isRMOpcode(unsigned Opcode) {
+ switch (Opcode) {
+ case Lanai::LDW_RI:
+ case Lanai::SW_RI:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool isRRMOpcode(unsigned Opcode) {
+ switch (Opcode) {
+ case Lanai::LDBs_RR:
+ case Lanai::LDBz_RR:
+ case Lanai::LDHs_RR:
+ case Lanai::LDHz_RR:
+ case Lanai::LDWz_RR:
+ case Lanai::LDW_RR:
+ case Lanai::STB_RR:
+ case Lanai::STH_RR:
+ case Lanai::SW_RR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_LANAI_LANAIINSTRINFO_H
diff --git a/lib/Target/Lanai/LanaiInstrInfo.td b/lib/Target/Lanai/LanaiInstrInfo.td
new file mode 100644
index 00000000000..7565920f1f2
--- /dev/null
+++ b/lib/Target/Lanai/LanaiInstrInfo.td
@@ -0,0 +1,881 @@
+//===-- 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 : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant((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 : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant((uint64_t)N->getZExtValue() >> 16, SDLoc(N),
+ MVT::i32);
+}]>;
+
+def NEG : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(-N->getSExtValue(), SDLoc(N), MVT::i32);
+}]>;
+
+def LO21 : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant((uint64_t)N->getZExtValue() & 0x1fffff,
+ SDLoc(N), MVT::i32);
+}]>;
+
+// Branch targets
+def BrTargetAsmOperand : AsmOperandClass {
+ let Name = "BrTarget";
+}
+def BrTarget : Operand<OtherVT> {
+ let ParserMatchClass = BrTargetAsmOperand;
+ let EncoderMethod = "getBranchTargetOpValue";
+ let DecoderMethod = "decodeBranch";
+}
+
+def CallTargetAsmOperand : AsmOperandClass {
+ let Name = "CallTarget";
+}
+def CallTarget : Operand<i32> {
+ let ParserMatchClass = CallTargetAsmOperand;
+ let EncoderMethod = "getBranchTargetOpValue";
+ let DecoderMethod = "decodeBranch";
+}
+
+def ImmShiftAsmOperand : AsmOperandClass { let Name = "ImmShift"; }
+def immShift : Operand<i32>, PatLeaf<(imm), [{
+ int Imm = N->getSExtValue();
+ return Imm >= -31 && Imm <= 31;}]> {
+ let ParserMatchClass = ImmShiftAsmOperand;
+ let DecoderMethod = "decodeShiftImm";
+}
+
+def Imm10AsmOperand : AsmOperandClass { let Name = "Imm10"; }
+def imm10 : Operand<i32>, 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<i32>, 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<i32>, PatLeaf<(i32 imm), [{
+ // i32neg16 predicate - true if the 32-bit immediate is negative and can
+ // be represented by a 16 bit integer.
+ int Imm = N->getSExtValue();
+ return (Imm < 0) && (isInt<16>(Imm));}], LO16> {
+ let ParserMatchClass = LoImm16AsmOperand;
+}
+def i32lo16s : Operand<i32>, 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<i32>, 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<i32>, 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<i32>, 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<i32>, 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<i32> {
+ let PrintMethod = "printAluOperand";
+}
+
+// Addressing modes.
+def ADDRrr : ComplexPattern<i32, 3, "selectAddrRr", [], []>;
+def ADDRri : ComplexPattern<i32, 3, "selectAddrRi", [frameindex], []>;
+def ADDRsls : ComplexPattern<i32, 1, "selectAddrSls", [frameindex], []>;
+def ADDRspls : ComplexPattern<i32, 3, "selectAddrSpls", [frameindex], []>;
+
+// Address operands
+def MemRegImmAsmOperand : AsmOperandClass {
+ let Name = "MemRegImm";
+ let ParserMethod = "parseMemoryOperand";
+}
+def MEMri : Operand<i32> {
+ 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<i32> {
+ 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<i32> {
+ let MIOperandInfo = (ops i32lo21:$offset);
+ let ParserMatchClass = MemImmAsmOperand;
+ let PrintMethod = "printMemImmOperand";
+}
+
+def MemSplsAsmOperand : AsmOperandClass {
+ let Name = "MemSpls";
+ let ParserMethod = "parseMemoryOperand";
+}
+def MEMspls : Operand<i32> {
+ let DecoderMethod = "decodeSplsValue";
+ let EncoderMethod = "getSplsOpValue";
+ let MIOperandInfo = (ops GPR:$base, imm10:$offset, AluOp:$Opcode);
+ let ParserMatchClass = MemSplsAsmOperand;
+ let PrintMethod = "printMemSplsOperand";
+}
+
+def CCOp : Operand<i32> {
+ 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<bits<3> subOp, string AsmStr, SDNode OpNode,
+ PatLeaf LoExt, PatLeaf HiExt,
+ list<dag> loPattern, list<dag> hiPattern> {
+ // Register Immediate
+ let H = 0 in
+ def LO : InstRI<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, LoExt:$imm16),
+ !strconcat(AsmStr, "\t$Rs1, $imm16, $Rd"),
+ loPattern>;
+ let H = 1 in
+ def HI : InstRI<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, HiExt:$imm16),
+ !strconcat(AsmStr, "\t$Rs1, $imm16, $Rd"),
+ hiPattern>;
+
+}
+
+multiclass ALUarith<bits<3> subOp, string AsmStr, SDNode OpNode,
+ PatLeaf LoExt, PatLeaf HiExt> {
+ defm I_ : ALUbase<subOp, AsmStr, OpNode, LoExt, HiExt, [], []>;
+
+ // Register Register
+ let JJJJJ = 0, DDDI = 0 in
+ def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2),
+ !strconcat(AsmStr, "\t$Rs1, $Rs2, $Rd"),
+ [(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>;
+ // RR Conditional
+ let JJJJJ = 0, Uses = [SR] in
+ def R_CC : InstRR<subOp, (outs GPR:$Rd),
+ (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI),
+ !strconcat(AsmStr, ".$DDDI\t$Rs1, $Rs2, $Rd"),
+ []>;
+}
+
+multiclass ALUlogic<bits<3> subOp, string AsmStr, SDNode OpNode,
+ PatLeaf LoExt, PatLeaf HiExt> {
+ defm I_ : ALUbase<subOp, AsmStr, OpNode, LoExt, HiExt,
+ [(set GPR:$Rd, (OpNode GPR:$Rs1, LoExt:$imm16))],
+ [(set GPR:$Rd, (OpNode GPR:$Rs1, HiExt:$imm16))]>;
+
+ // Register Register
+ let JJJJJ = 0, DDDI = 0 in
+ def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2),
+ !strconcat(AsmStr, "\t$Rs1, $Rs2, $Rd"),
+ [(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>;
+ // RR Conditional
+ let JJJJJ = 0, Uses = [SR] in
+ def R_CC : InstRR<subOp, (outs GPR:$Rd),
+ (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI),
+ !strconcat(AsmStr, ".$DDDI\t$Rs1, $Rs2, $Rd"),
+ []>;
+}
+
+// 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<string AsmStr, list<dag> Pattern>
+ : InstRI<0b111, (outs GPR:$Rd), (ins GPR:$Rs1, immShift:$imm16),
+ !strconcat(AsmStr, "\t$Rs1, $imm16, $Rd"), Pattern> {
+ let isReMaterializable = 1;
+}
+
+let F = 0 in {
+ let H = 0 in
+ def SL_I : ShiftRI<"sh", [(set GPR:$Rd, (shl GPR:$Rs1, immShift:$imm16))]>;
+ let H = 1 in
+ def SA_I : ShiftRI<"sha", []>;
+}
+def : Pat<(srl GPR:$Rs1, immShift:$imm), (SL_I GPR:$Rs1, (NEG $imm))>;
+def : Pat<(sra GPR:$Rs1, immShift:$imm), (SA_I GPR:$Rs1, (NEG $imm))>;
+
+let F = 1, Defs = [SR] in {
+ let H = 0 in
+ def SL_F_I : ShiftRI<"sh.f", []>;
+ let H = 1 in
+ def SA_F_I : ShiftRI<"sha.f", []>;
+}
+
+class ShiftRR<string AsmStr, list<dag> 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<string OpcString, PatFrag OpNode, ValueType Ty>
+ : 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<string OpcString, PatFrag OpNode, ValueType Ty>
+ : 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<string asmstring, PatFrag opNode>
+ : 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<string OpcString, PatFrag OpNode, ValueType Ty>
+ : 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<string OpcString, PatFrag OpNode, ValueType Ty>
+ : 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<string asmstring, PatFrag opNode>
+ : 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<bits<3> op2Val, string AsmStr> {
+ let F = 1, Rd = R0.Num, JJJJJ = 0, Defs = [SR], DDDI = 0 in
+ def _RR : InstRR<op2Val, (outs), (ins GPR:$Rs1, GPR:$Rs2),
+ !strconcat(AsmStr, "\t$Rs1, $Rs2, %r0"),
+ [(LanaiSetFlag (i32 GPR:$Rs1), (i32 GPR:$Rs2))]>;
+ let F = 1, Rd = R0.Num, H = 0, Defs = [SR] in
+ def _RI : InstRI<op2Val, (outs), (ins GPR:$Rs1, i32lo16s:$imm16),
+ !strconcat(AsmStr, "\t$Rs1, $imm16, %r0"),
+ [(LanaiSetFlag (i32 GPR:$Rs1), i32lo16s:$imm16)]>;
+}
+let isCodeGenOnly = 1 in {
+ defm SFSUB_F : SF<0b010, "sub.f">;
+}
+
+// Jump and link
+let isCall = 1, hasDelaySlot = 1, isCodeGenOnly = 1, Uses = [SP],
+ Defs = [RCA] in {
+ def CALL : Pseudo<(outs), (ins CallTarget:$addr), "", []>;
+ def CALLR : Pseudo<(outs), (ins GPR:$Rs1), "", [(Call GPR:$Rs1)]>;
+}
+
+let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1,
+ Uses = [RCA] 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)>;
diff --git a/lib/Target/Lanai/LanaiMCInstLower.cpp b/lib/Target/Lanai/LanaiMCInstLower.cpp
new file mode 100644
index 00000000000..98c5447d270
--- /dev/null
+++ b/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);
+ }
+}
diff --git a/lib/Target/Lanai/LanaiMCInstLower.h b/lib/Target/Lanai/LanaiMCInstLower.h
new file mode 100644
index 00000000000..9ea8a36c1ef
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/LanaiMachineFunctionInfo.cpp b/lib/Target/Lanai/LanaiMachineFunctionInfo.cpp
new file mode 100644
index 00000000000..c72271b6779
--- /dev/null
+++ b/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);
+}
diff --git a/lib/Target/Lanai/LanaiMachineFunctionInfo.h b/lib/Target/Lanai/LanaiMachineFunctionInfo.h
new file mode 100644
index 00000000000..3bd9112a9e1
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/LanaiMemAluCombiner.cpp b/lib/Target/Lanai/LanaiMemAluCombiner.cpp
new file mode 100644
index 00000000000..40d3418e45f
--- /dev/null
+++ b/lib/Target/Lanai/LanaiMemAluCombiner.cpp
@@ -0,0 +1,414 @@
+//===-- 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<bool> 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 *TII;
+};
+} // 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_R:
+ return LPAC::SHL;
+ case Lanai::SRL_R:
+ return LPAC::SRL;
+ case Lanai::SRA_R:
+ return LPAC::SRA;
+ case Lanai::SA_I:
+ case Lanai::SL_I:
+ 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(), TII->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<LPAC::AluCode>(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) {
+ if (DisableMemAluCombiner)
+ return false;
+
+ TII = MF.getSubtarget<LanaiSubtarget>().getInstrInfo();
+ bool Modified = false;
+ for (MfIterator MFI = MF.begin(); MFI != MF.end(); ++MFI) {
+ Modified |= combineMemAluInBasicBlock(&*MFI);
+ }
+ return Modified;
+}
+} // namespace
+
+FunctionPass *llvm::createLanaiMemAluCombinerPass() {
+ return new LanaiMemAluCombiner();
+}
diff --git a/lib/Target/Lanai/LanaiRegisterInfo.cpp b/lib/Target/Lanai/LanaiRegisterInfo.cpp
new file mode 100644
index 00000000000..43524042cb4
--- /dev/null
+++ b/lib/Target/Lanai/LanaiRegisterInfo.cpp
@@ -0,0 +1,282 @@
+//===-- 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()
+ : LanaiGenRegisterInfo(Lanai::RCA) {}
+
+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 TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ 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<uint32_t>(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
+ 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;
+}
diff --git a/lib/Target/Lanai/LanaiRegisterInfo.h b/lib/Target/Lanai/LanaiRegisterInfo.h
new file mode 100644
index 00000000000..8b84bbc460e
--- /dev/null
+++ b/lib/Target/Lanai/LanaiRegisterInfo.h
@@ -0,0 +1,63 @@
+//===- 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 {
+ LanaiRegisterInfo();
+
+ 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
diff --git a/lib/Target/Lanai/LanaiRegisterInfo.td b/lib/Target/Lanai/LanaiRegisterInfo.td
new file mode 100644
index 00000000000..cf8cfe30cce
--- /dev/null
+++ b/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<bits<5> num, string n, list<Register> subregs = [],
+ list<string> altNames = []> : Register<n, altNames> {
+ 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<i, "r"#i>, DwarfRegNum<[i]>;
+}
+
+// Register aliases
+let SubRegIndices = [sub_32] in {
+ def PC : LanaiReg< 2, "pc", [R2]>, DwarfRegAlias<R2>;
+ def SP : LanaiReg< 4, "sp", [R4]>, DwarfRegAlias<R4>;
+ def FP : LanaiReg< 5, "fp", [R5]>, DwarfRegAlias<R5>;
+ def RV : LanaiReg< 8, "rv", [R8]>, DwarfRegAlias<R8>;
+ def RR1 : LanaiReg<10, "rr1", [R10]>, DwarfRegAlias<R10>;
+ def RR2 : LanaiReg<11, "rr2", [R11]>, DwarfRegAlias<R11>;
+ def RCA : LanaiReg<15, "rca", [R15]>, DwarfRegAlias<R15>;
+}
+
+// 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;
+}
diff --git a/lib/Target/Lanai/LanaiSchedule.td b/lib/Target/Lanai/LanaiSchedule.td
new file mode 100644
index 00000000000..949a2e28bef
--- /dev/null
+++ b/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<IIC_LD, [InstrStage<1, [LDST_FU]>]>,
+ InstrItinData<IIC_ST, [InstrStage<1, [LDST_FU]>]>,
+ InstrItinData<IIC_ALU, [InstrStage<1, [ALU_FU]>]>
+]>;
+
+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<WriteLD, [LdSt]> { let Latency = 2; }
+ def : WriteRes<WriteST, [LdSt]> { let Latency = 2; }
+ def : WriteRes<WriteALU, [ALU]> { let Latency = 1; }
+}
diff --git a/lib/Target/Lanai/LanaiSelectionDAGInfo.cpp b/lib/Target/Lanai/LanaiSelectionDAGInfo.cpp
new file mode 100644
index 00000000000..d4eed72d742
--- /dev/null
+++ b/lib/Target/Lanai/LanaiSelectionDAGInfo.cpp
@@ -0,0 +1,33 @@
+//===-- 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 {
+ ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
+ if (!ConstantSize)
+ return SDValue();
+
+ return SDValue();
+}
+
+} // namespace llvm
diff --git a/lib/Target/Lanai/LanaiSelectionDAGInfo.h b/lib/Target/Lanai/LanaiSelectionDAGInfo.h
new file mode 100644
index 00000000000..1f1f9ef1513
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp b/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp
new file mode 100644
index 00000000000..973025da1fc
--- /dev/null
+++ b/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp
@@ -0,0 +1,327 @@
+//===-- 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<bool> 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);
+};
+} // 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::SL_I:
+ return Lanai::SL_F_I;
+ case Lanai::SRL_R:
+ return Lanai::SRL_F_R;
+ case Lanai::SA_I:
+ return Lanai::SA_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::SA_F_I:
+ case Lanai::SL_F_I:
+ case Lanai::SHL_F_R:
+ case Lanai::SRA_F_R:
+ 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<LPCC::CondCode>(
+ 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;
+ const TargetInstrInfo *TII =
+ MF->getSubtarget<LanaiSubtarget>().getInstrInfo();
+
+ 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;
+
+ 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();
+}
diff --git a/lib/Target/Lanai/LanaiSubtarget.cpp b/lib/Target/Lanai/LanaiSubtarget.cpp
new file mode 100644
index 00000000000..98b93401631
--- /dev/null
+++ b/lib/Target/Lanai/LanaiSubtarget.cpp
@@ -0,0 +1,48 @@
+//===- 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::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, const TargetMachine &TM,
+ const TargetOptions &Options,
+ Reloc::Model RelocationModel,
+ CodeModel::Model CodeModel,
+ CodeGenOpt::Level OptLevel)
+ : LanaiGenSubtargetInfo(TargetTriple, Cpu, FeatureString),
+ FrameLowering(initializeSubtargetDependencies(Cpu, FeatureString)),
+ InstrInfo(), TLInfo(TM, *this), TSInfo() {}
diff --git a/lib/Target/Lanai/LanaiSubtarget.h b/lib/Target/Lanai/LanaiSubtarget.h
new file mode 100644
index 00000000000..f50347682e2
--- /dev/null
+++ b/lib/Target/Lanai/LanaiSubtarget.h
@@ -0,0 +1,76 @@
+//=====-- 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 "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, const 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 &InstrInfo; }
+
+ const TargetFrameLowering *getFrameLowering() const override {
+ return &FrameLowering;
+ }
+
+ const LanaiRegisterInfo *getRegisterInfo() const override {
+ return &InstrInfo.getRegisterInfo();
+ }
+
+ const LanaiTargetLowering *getTargetLowering() const override {
+ return &TLInfo;
+ }
+
+ const LanaiSelectionDAGInfo *getSelectionDAGInfo() const override {
+ return &TSInfo;
+ }
+
+private:
+ LanaiFrameLowering FrameLowering;
+ LanaiInstrInfo InstrInfo;
+ LanaiTargetLowering TLInfo;
+ LanaiSelectionDAGInfo TSInfo;
+};
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_LANAI_LANAISUBTARGET_H
diff --git a/lib/Target/Lanai/LanaiTargetMachine.cpp b/lib/Target/Lanai/LanaiTargetMachine.cpp
new file mode 100644
index 00000000000..476ab680d91
--- /dev/null
+++ b/lib/Target/Lanai/LanaiTargetMachine.cpp
@@ -0,0 +1,110 @@
+//===-- 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<LanaiTargetMachine> 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, 32 bit 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<LanaiTargetMachine>();
+ }
+
+ 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() {
+ addPass(createLanaiMemAluCombinerPass());
+ addPass(createLanaiSetflagAluCombinerPass());
+}
diff --git a/lib/Target/Lanai/LanaiTargetMachine.h b/lib/Target/Lanai/LanaiTargetMachine.h
new file mode 100644
index 00000000000..9c911768e30
--- /dev/null
+++ b/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<TargetLoweringObjectFile> 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
diff --git a/lib/Target/Lanai/LanaiTargetObjectFile.cpp b/lib/Target/Lanai/LanaiTargetObjectFile.cpp
new file mode 100644
index 00000000000..a4a6de859cb
--- /dev/null
+++ b/lib/Target/Lanai/LanaiTargetObjectFile.cpp
@@ -0,0 +1,123 @@
+//
+// 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<unsigned> 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);
+}
+
+// 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<GlobalVariable>(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 {
+ return isInSmallSection(DL.getTypeAllocSize(CN->getType()));
+}
+
+MCSection *LanaiTargetObjectFile::getSectionForConstant(const DataLayout &DL,
+ SectionKind Kind,
+ const Constant *C,
+ unsigned &Align) const {
+ if (isConstantInSmallSection(DL, C))
+ return SmallDataSection;
+
+ // Otherwise, we work the same as ELF.
+ return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align);
+}
diff --git a/lib/Target/Lanai/LanaiTargetObjectFile.h b/lib/Target/Lanai/LanaiTargetObjectFile.h
new file mode 100644
index 00000000000..eb5195469f5
--- /dev/null
+++ b/lib/Target/Lanai/LanaiTargetObjectFile.h
@@ -0,0 +1,46 @@
+//===-- 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;
+
+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;
+
+ MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind,
+ const Constant *C,
+ unsigned &Align) const override;
+};
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_LANAI_LANAITARGETOBJECTFILE_H
diff --git a/lib/Target/Lanai/LanaiTargetTransformInfo.h b/lib/Target/Lanai/LanaiTargetTransformInfo.h
new file mode 100644
index 00000000000..755f0aa1663
--- /dev/null
+++ b/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<LanaiTTIImpl> {
+ typedef BasicTTIImplBase<LanaiTTIImpl> 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<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
+ LanaiTTIImpl(LanaiTTIImpl &&Arg)
+ : BaseT(std::move(static_cast<BaseT &>(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
diff --git a/lib/Target/Lanai/MCTargetDesc/CMakeLists.txt b/lib/Target/Lanai/MCTargetDesc/CMakeLists.txt
new file mode 100644
index 00000000000..d65a1fd5890
--- /dev/null
+++ b/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
+)
diff --git a/lib/Target/Lanai/MCTargetDesc/LLVMBuild.txt b/lib/Target/Lanai/MCTargetDesc/LLVMBuild.txt
new file mode 100644
index 00000000000..7dc2a7694ab
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp b/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp
new file mode 100644
index 00000000000..d3a075cef16
--- /dev/null
+++ b/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp
@@ -0,0 +1,168 @@
+//===-- 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<unsigned>(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<uint64_t>(static_cast<uint8_t>(Data[Offset + Idx]))
+ << (i * 8);
+ }
+
+ uint64_t Mask =
+ (static_cast<uint64_t>(-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<uint8_t>((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.isOSBinFormatELF())
+ llvm_unreachable("OS not supported");
+
+ return new LanaiAsmBackend(T, TheTriple.getOS());
+}
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h b/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h
new file mode 100644
index 00000000000..42bda1e894f
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp b/lib/Target/Lanai/MCTargetDesc/LanaiELFObjectWriter.cpp
new file mode 100644
index 00000000000..d11eb0ab81d
--- /dev/null
+++ b/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<unsigned>(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);
+}
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiFixupKinds.h b/lib/Target/Lanai/MCTargetDesc/LanaiFixupKinds.h
new file mode 100644
index 00000000000..9ff8340d292
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.cpp b/lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.cpp
new file mode 100644
index 00000000000..491a7084757
--- /dev/null
+++ b/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;
+}
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.h b/lib/Target/Lanai/MCTargetDesc/LanaiMCAsmInfo.h
new file mode 100644
index 00000000000..054e7fd3504
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp b/lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp
new file mode 100644
index 00000000000..b4ffa7c23bf
--- /dev/null
+++ b/lib/Target/Lanai/MCTargetDesc/LanaiMCCodeEmitter.cpp
@@ -0,0 +1,325 @@
+//===-- 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<MCFixup> &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<MCFixup> &Fixups,
+ const MCSubtargetInfo &SubtargetInfo) const;
+
+ unsigned getRiMemoryOpValue(const MCInst &Inst, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &SubtargetInfo) const;
+
+ unsigned getRrMemoryOpValue(const MCInst &Inst, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &SubtargetInfo) const;
+
+ unsigned getSplsOpValue(const MCInst &Inst, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &SubtargetInfo) const;
+
+ unsigned getBranchTargetOpValue(const MCInst &Inst, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &SubtargetInfo) const;
+
+ unsigned getCallTargetOpValue(const MCInst &Inst, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &SubtargetInfo) const;
+
+ void encodeInstruction(const MCInst &Inst, raw_ostream &Ostream,
+ SmallVectorImpl<MCFixup> &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<MCSymbolRefExpr>(Expr))
+ return Lanai::FIXUP_LANAI_21;
+ if (const LanaiMCExpr *McExpr = dyn_cast<LanaiMCExpr>(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<MCFixup> &Fixups,
+ const MCSubtargetInfo &SubtargetInfo) const {
+ if (MCOp.isReg())
+ return getLanaiRegisterNumbering(MCOp.getReg());
+ if (MCOp.isImm())
+ return static_cast<unsigned>(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<const MCBinaryExpr *>(Expr);
+ Expr = BinaryExpr->getLHS();
+ }
+
+ assert(isa<LanaiMCExpr>(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<MCFixup> &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<char>((Value >> i) & 0xff);
+}
+
+// Encode Lanai Memory Operand
+unsigned LanaiMCCodeEmitter::getRiMemoryOpValue(
+ const MCInst &Inst, unsigned OpNo, SmallVectorImpl<MCFixup> &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<MCFixup> &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<MCFixup> &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::getCallTargetOpValue(
+ const MCInst &Inst, unsigned OpNo, SmallVectorImpl<MCFixup> &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<MCFixupKind>(Lanai::FIXUP_LANAI_25)));
+
+ return 0;
+}
+
+unsigned LanaiMCCodeEmitter::getBranchTargetOpValue(
+ const MCInst &Inst, unsigned OpNo, SmallVectorImpl<MCFixup> &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<MCFixupKind>(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);
+}
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.cpp b/lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.cpp
new file mode 100644
index 00000000000..201c95de07f
--- /dev/null
+++ b/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;
+}
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.h b/lib/Target/Lanai/MCTargetDesc/LanaiMCExpr.h
new file mode 100644
index 00000000000..f481b039bda
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp b/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp
new file mode 100644
index 00000000000..9db240100b4
--- /dev/null
+++ b/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.cpp
@@ -0,0 +1,163 @@
+//===-- 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.isOSBinFormatELF())
+ llvm_unreachable("OS not supported");
+
+ 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<LanaiMCAsmInfo> 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);
+}
diff --git a/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h b/lib/Target/Lanai/MCTargetDesc/LanaiMCTargetDesc.h
new file mode 100644
index 00000000000..e117ed7a500
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/TargetInfo/CMakeLists.txt b/lib/Target/Lanai/TargetInfo/CMakeLists.txt
new file mode 100644
index 00000000000..01611b54b2d
--- /dev/null
+++ b/lib/Target/Lanai/TargetInfo/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_llvm_library(LLVMLanaiInfo
+ LanaiTargetInfo.cpp
+ )
diff --git a/lib/Target/Lanai/TargetInfo/LLVMBuild.txt b/lib/Target/Lanai/TargetInfo/LLVMBuild.txt
new file mode 100644
index 00000000000..9922ec36daa
--- /dev/null
+++ b/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
diff --git a/lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp b/lib/Target/Lanai/TargetInfo/LanaiTargetInfo.cpp
new file mode 100644
index 00000000000..bd615d6ad3a
--- /dev/null
+++ b/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<Triple::lanai> X(TheLanaiTarget, "lanai", "Lanai");
+}
diff --git a/test/CodeGen/Lanai/codemodel.ll b/test/CodeGen/Lanai/codemodel.ll
new file mode 100644
index 00000000000..e5ec7265924
--- /dev/null
+++ b/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 ; <i32> [#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 ; <i32> [#uses=1]
+ ret i32 %0
+}
+
diff --git a/test/CodeGen/Lanai/combined_alu_setcc.ll b/test/CodeGen/Lanai/combined_alu_setcc.ll
new file mode 100644
index 00000000000..5f035b20fa1
--- /dev/null
+++ b/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
diff --git a/test/CodeGen/Lanai/comparisons_i32.ll b/test/CodeGen/Lanai/comparisons_i32.ll
new file mode 100644
index 00000000000..fd8ca725c4c
--- /dev/null
+++ b/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
+}
diff --git a/test/CodeGen/Lanai/constant_multiply.ll b/test/CodeGen/Lanai/constant_multiply.ll
new file mode 100644
index 00000000000..77c9805e441
--- /dev/null
+++ b/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
+}
diff --git a/test/CodeGen/Lanai/delay_filler.ll b/test/CodeGen/Lanai/delay_filler.ll
new file mode 100644
index 00000000000..bb74276d46d
--- /dev/null
+++ b/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
+
diff --git a/test/CodeGen/Lanai/i32.ll b/test/CodeGen/Lanai/i32.ll
new file mode 100644
index 00000000000..632cc467d68
--- /dev/null
+++ b/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
+}
diff --git a/test/CodeGen/Lanai/lit.local.cfg b/test/CodeGen/Lanai/lit.local.cfg
new file mode 100644
index 00000000000..3f30d055364
--- /dev/null
+++ b/test/CodeGen/Lanai/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'Lanai' in config.root.targets:
+ config.unsupported = True
+
diff --git a/test/CodeGen/Lanai/mem_alu_combiner.ll b/test/CodeGen/Lanai/mem_alu_combiner.ll
new file mode 100644
index 00000000000..087ea1cc146
--- /dev/null
+++ b/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"}
diff --git a/test/CodeGen/Lanai/multiply.ll b/test/CodeGen/Lanai/multiply.ll
new file mode 100644
index 00000000000..c92a06c3f01
--- /dev/null
+++ b/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
diff --git a/test/CodeGen/Lanai/select.ll b/test/CodeGen/Lanai/select.ll
new file mode 100644
index 00000000000..159e8edb283
--- /dev/null
+++ b/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
+}
diff --git a/test/CodeGen/Lanai/set_and_hi.ll b/test/CodeGen/Lanai/set_and_hi.ll
new file mode 100644
index 00000000000..bfce094050c
--- /dev/null
+++ b/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
+}
diff --git a/test/CodeGen/Lanai/shift.ll b/test/CodeGen/Lanai/shift.ll
new file mode 100644
index 00000000000..df5f91122ed
--- /dev/null
+++ b/test/CodeGen/Lanai/shift.ll
@@ -0,0 +1,28 @@
+; RUN: llc < %s -march=lanai | FileCheck %s
+
+; Test lowering of shifts.
+
+define i32 @irs(i32 inreg %a) #0 {
+entry:
+ %shr = ashr i32 %a, 13
+ ret i32 %shr
+}
+; CHECK-LABEL: irs
+; CHECK: sha %r6, -0xd, %rv
+
+define i32 @urs(i32 inreg %a) #0 {
+entry:
+ %shr = lshr i32 %a, 13
+ ret i32 %shr
+}
+; CHECK-LABEL: urs
+; CHECK: sh %r6, -0xd, %rv
+
+define i32 @ls(i32 inreg %a) #0 {
+entry:
+ %shl = shl i32 %a, 13
+ ret i32 %shl
+}
+; CHECK-LABEL: ls
+; CHECK: sh %r6, 0xd, %rv
+
diff --git a/test/CodeGen/Lanai/stack-frame.ll b/test/CodeGen/Lanai/stack-frame.ll
new file mode 100644
index 00000000000..3564658fa0f
--- /dev/null
+++ b/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
diff --git a/test/DebugInfo/Inputs/lanai-processes-relocations.elf b/test/DebugInfo/Inputs/lanai-processes-relocations.elf
deleted file mode 100644
index 88d519a2cdf..00000000000
--- a/test/DebugInfo/Inputs/lanai-processes-relocations.elf
+++ /dev/null
Binary files differ
diff --git a/test/DebugInfo/Lanai/processes-relocations.ll b/test/DebugInfo/Lanai/processes-relocations.ll
index 1fdf4a37fae..4f8138a8724 100644
--- a/test/DebugInfo/Lanai/processes-relocations.ll
+++ b/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 "}
diff --git a/test/MC/Disassembler/Lanai/lit.local.cfg b/test/MC/Disassembler/Lanai/lit.local.cfg
new file mode 100644
index 00000000000..3f30d055364
--- /dev/null
+++ b/test/MC/Disassembler/Lanai/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'Lanai' in config.root.targets:
+ config.unsupported = True
+
diff --git a/test/MC/Disassembler/Lanai/v11.txt b/test/MC/Disassembler/Lanai/v11.txt
new file mode 100644
index 00000000000..8e956f93e20
--- /dev/null
+++ b/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
diff --git a/test/MC/Lanai/lit.local.cfg b/test/MC/Lanai/lit.local.cfg
new file mode 100644
index 00000000000..3f30d055364
--- /dev/null
+++ b/test/MC/Lanai/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'Lanai' in config.root.targets:
+ config.unsupported = True
+
diff --git a/test/MC/Lanai/v11.s b/test/MC/Lanai/v11.s
new file mode 100644
index 00000000000..416b34e4981
--- /dev/null
+++ b/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
+
+
diff --git a/test/Object/Lanai/yaml2obj-elf-lanai-rel.yaml b/test/Object/Lanai/yaml2obj-elf-lanai-rel.yaml
index 3a31a3901a2..aa45ca16b34 100644
--- a/test/Object/Lanai/yaml2obj-elf-lanai-rel.yaml
+++ b/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