1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[lanai] Add Lanai backend.

Add the Lanai backend to lib/Target.

General Lanai backend discussion on llvm-dev thread "[RFC] Lanai backend" (http://lists.llvm.org/pipermail/llvm-dev/2016-February/095118.html).

Differential Revision: http://reviews.llvm.org/D17011

llvm-svn: 264578
This commit is contained in:
Jacques Pienaar 2016-03-28 13:09:54 +00:00
parent d84de52bea
commit 9af311f3de
87 changed files with 12430 additions and 8 deletions

View File

@ -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

View File

@ -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");
}

View File

@ -25,6 +25,7 @@ subdirectories =
AVR
BPF
CppBackend
Lanai
Hexagon
MSP430
NVPTX

View File

@ -0,0 +1,7 @@
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. )
add_llvm_library(LLVMLanaiAsmParser
LanaiAsmParser.cpp
)
add_dependencies( LLVMLanaiAsmParser LanaiCommonTableGen )

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMLanaiDisassembler
LanaiDisassembler.cpp
)

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMLanaiInstPrinter
LanaiInstPrinter.cpp
)

View File

@ -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

View File

@ -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));
}

View File

@ -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

View File

@ -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

51
lib/Target/Lanai/Lanai.h Normal file
View File

@ -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

47
lib/Target/Lanai/Lanai.td Normal file
View File

@ -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];
}

View File

@ -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

View File

@ -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);
}

View File

@ -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)>;

View File

@ -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

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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)>;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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; }
}

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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() {}

View File

@ -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

View File

@ -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());
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,8 @@
add_llvm_library(LLVMLanaiMCTargetDesc
LanaiAsmBackend.cpp
LanaiELFObjectWriter.cpp
LanaiMCAsmInfo.cpp
LanaiMCCodeEmitter.cpp
LanaiMCExpr.cpp
LanaiMCTargetDesc.cpp
)

View File

@ -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

View File

@ -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());
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMLanaiInfo
LanaiTargetInfo.cpp
)

View File

@ -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

View File

@ -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");
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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

145
test/CodeGen/Lanai/i32.ll Normal file
View File

@ -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
}

View File

@ -0,0 +1,3 @@
if not 'Lanai' in config.root.targets:
config.unsupported = True

View File

@ -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"}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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 "}

View File

@ -0,0 +1,3 @@
if not 'Lanai' in config.root.targets:
config.unsupported = True

View File

@ -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

View File

@ -0,0 +1,3 @@
if not 'Lanai' in config.root.targets:
config.unsupported = True

830
test/MC/Lanai/v11.s Normal file
View File

@ -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

View File

@ -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