1,162 changes: 1,162 additions & 0 deletions llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions llvm/lib/Target/Lanai/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
set(LLVM_TARGET_DEFINITIONS Lanai.td)

tablegen(LLVM LanaiGenAsmMatcher.inc -gen-asm-matcher)
tablegen(LLVM LanaiGenAsmWriter.inc -gen-asm-writer)
tablegen(LLVM LanaiGenCallingConv.inc -gen-callingconv)
tablegen(LLVM LanaiGenDAGISel.inc -gen-dag-isel)
tablegen(LLVM LanaiGenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM LanaiGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM LanaiGenMCCodeEmitter.inc -gen-emitter)
tablegen(LLVM LanaiGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM LanaiGenSubtargetInfo.inc -gen-subtarget)
add_public_tablegen_target(LanaiCommonTableGen)

add_llvm_target(LanaiCodeGen
LanaiAsmPrinter.cpp
LanaiDelaySlotFiller.cpp
LanaiFrameLowering.cpp
LanaiInstrInfo.cpp
LanaiISelDAGToDAG.cpp
LanaiISelLowering.cpp
LanaiMachineFunctionInfo.cpp
LanaiMCInstLower.cpp
LanaiMemAluCombiner.cpp
LanaiRegisterInfo.cpp
LanaiSelectionDAGInfo.cpp
LanaiSetflagAluCombiner.cpp
LanaiSubtarget.cpp
LanaiTargetMachine.cpp
LanaiTargetObjectFile.cpp
)

add_subdirectory(AsmParser)
add_subdirectory(TargetInfo)
add_subdirectory(MCTargetDesc)
add_subdirectory(InstPrinter)
add_subdirectory(Disassembler)
3 changes: 3 additions & 0 deletions llvm/lib/Target/Lanai/Disassembler/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_llvm_library(LLVMLanaiDisassembler
LanaiDisassembler.cpp
)
23 changes: 23 additions & 0 deletions llvm/lib/Target/Lanai/Disassembler/LLVMBuild.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
;===-- ./lib/Target/Lanai/Disassembler/LLVMBuild.txt -----------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;

[component_0]
type = Library
name = LanaiDisassembler
parent = Lanai
required_libraries = LanaiMCTargetDesc LanaiInfo MC MCDisassembler Support
add_to_library_groups = Lanai
228 changes: 228 additions & 0 deletions llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
//===- LanaiDisassembler.cpp - Disassembler for Lanai -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is part of the Lanai Disassembler.
//
//===----------------------------------------------------------------------===//

#include "LanaiDisassembler.h"

#include "Lanai.h"
#include "LanaiSubtarget.h"
#include "llvm/MC/MCFixedLenDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryObject.h"
#include "llvm/Support/TargetRegistry.h"

using namespace llvm;

typedef MCDisassembler::DecodeStatus DecodeStatus;

namespace llvm {
extern Target TheLanaiTarget;
}

static MCDisassembler *createLanaiDisassembler(const Target &T,
const MCSubtargetInfo &STI,
MCContext &Ctx) {
return new LanaiDisassembler(STI, Ctx);
}

extern "C" void LLVMInitializeLanaiDisassembler() {
// Register the disassembler
TargetRegistry::RegisterMCDisassembler(TheLanaiTarget,
createLanaiDisassembler);
}

LanaiDisassembler::LanaiDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
: MCDisassembler(STI, Ctx) {}

// Forward declare because the autogenerated code will reference this.
// Definition is further down.
DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder);

static DecodeStatus decodeRiMemoryValue(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder);

static DecodeStatus decodeRrMemoryValue(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder);

static DecodeStatus decodeSplsValue(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder);

static DecodeStatus decodeBranch(MCInst &Inst, unsigned Insn, uint64_t Address,
const void *Decoder);

static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder);

#include "LanaiGenDisassemblerTables.inc"

static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
uint64_t &Size, uint32_t &Insn) {
// We want to read exactly 4 bytes of data.
if (Bytes.size() < 4) {
Size = 0;
return MCDisassembler::Fail;
}

// Encoded as big-endian 32-bit word in the stream.
Insn =
(Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 8) | (Bytes[3] << 0);

return MCDisassembler::Success;
}

static void PostOperandDecodeAdjust(MCInst &Instr, uint32_t Insn) {
unsigned AluOp = LPAC::ADD;
// Fix up for pre and post operations.
int PqShift = -1;
if (isRMOpcode(Instr.getOpcode()))
PqShift = 16;
else if (isSPLSOpcode(Instr.getOpcode()))
PqShift = 10;
else if (isRRMOpcode(Instr.getOpcode())) {
PqShift = 16;
// Determine RRM ALU op.
AluOp = (Insn >> 8) & 0x7;
if (AluOp == 7)
// Handle JJJJJ
// 0b10000 or 0b11000
AluOp |= 0x20 | (((Insn >> 3) & 0xf) << 1);
}

if (PqShift != -1) {
unsigned PQ = (Insn >> PqShift) & 0x3;
switch (PQ) {
case 0x0:
if (Instr.getOperand(2).isReg()) {
Instr.getOperand(2).setReg(Lanai::R0);
}
if (Instr.getOperand(2).isImm())
Instr.getOperand(2).setImm(0);
break;
case 0x1:
AluOp = LPAC::makePostOp(AluOp);
break;
case 0x2:
break;
case 0x3:
AluOp = LPAC::makePreOp(AluOp);
break;
}
Instr.addOperand(MCOperand::createImm(AluOp));
}
}

DecodeStatus LanaiDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes,
uint64_t Address,
raw_ostream &VStream,
raw_ostream &CStream) const {
uint32_t Insn;

DecodeStatus Result = readInstruction32(Bytes, Address, Size, Insn);

if (Result == MCDisassembler::Fail)
return MCDisassembler::Fail;

// Call auto-generated decoder function
Result =
decodeInstruction(DecoderTableLanai32, Instr, Insn, Address, this, STI);

if (Result != MCDisassembler::Fail) {
PostOperandDecodeAdjust(Instr, Insn);
Size = 4;
return Result;
}

return MCDisassembler::Fail;
}

static const unsigned GPRDecoderTable[] = {
Lanai::R0, Lanai::R1, Lanai::PC, Lanai::R3, Lanai::SP, Lanai::FP,
Lanai::R6, Lanai::R7, Lanai::RV, Lanai::R9, Lanai::RR1, Lanai::RR2,
Lanai::R12, Lanai::R13, Lanai::R14, Lanai::RCA, Lanai::R16, Lanai::R17,
Lanai::R18, Lanai::R19, Lanai::R20, Lanai::R21, Lanai::R22, Lanai::R23,
Lanai::R24, Lanai::R25, Lanai::R26, Lanai::R27, Lanai::R28, Lanai::R29,
Lanai::R30, Lanai::R31};

DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;

unsigned Reg = GPRDecoderTable[RegNo];
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}

static DecodeStatus decodeRiMemoryValue(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder) {
// RI memory values encoded using 23 bits:
// 5 bit register, 16 bit constant
unsigned Register = (Insn >> 18) & 0x1f;
Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));
unsigned Offset = (Insn & 0xffff);
Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset)));

return MCDisassembler::Success;
}

static DecodeStatus decodeRrMemoryValue(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder) {
// RR memory values encoded using 20 bits:
// 5 bit register, 5 bit register, 2 bit PQ, 3 bit ALU operator, 5 bit JJJJJ
unsigned Register = (Insn >> 15) & 0x1f;
Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));
Register = (Insn >> 10) & 0x1f;
Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));

return MCDisassembler::Success;
}

static DecodeStatus decodeSplsValue(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder) {
// RI memory values encoded using 17 bits:
// 5 bit register, 10 bit constant
unsigned Register = (Insn >> 12) & 0x1f;
Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register]));
unsigned Offset = (Insn & 0x3ff);
Inst.addOperand(MCOperand::createImm(SignExtend32<10>(Offset)));

return MCDisassembler::Success;
}

static bool tryAddingSymbolicOperand(int64_t Value, bool IsBranch,
uint64_t Address, uint64_t Offset,
uint64_t Width, MCInst &MI,
const void *Decoder) {
const MCDisassembler *Dis = static_cast<const MCDisassembler *>(Decoder);
return Dis->tryAddingSymbolicOperand(MI, Value, Address, IsBranch, Offset,
Width);
}

static DecodeStatus decodeBranch(MCInst &MI, unsigned Insn, uint64_t Address,
const void *Decoder) {
if (!tryAddingSymbolicOperand(Insn + Address, false, Address, 2, 23, MI,
Decoder))
MI.addOperand(MCOperand::createImm(Insn));
return MCDisassembler::Success;
}

static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder) {
unsigned Offset = (Insn & 0xffff);
Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset)));

return MCDisassembler::Success;
}
41 changes: 41 additions & 0 deletions llvm/lib/Target/Lanai/Disassembler/LanaiDisassembler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===- LanaiDisassembler.cpp - Disassembler for Lanai -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is part of the Lanai Disassembler.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_LANAI_DISASSEMBLER_LANAIDISASSEMBLER_H
#define LLVM_LIB_TARGET_LANAI_DISASSEMBLER_LANAIDISASSEMBLER_H

#define DEBUG_TYPE "lanai-disassembler"

#include "llvm/MC/MCDisassembler/MCDisassembler.h"

namespace llvm {

class MCInst;
class raw_ostream;

class LanaiDisassembler : public MCDisassembler {
public:
LanaiDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx);

~LanaiDisassembler() override {}

// getInstruction - See MCDisassembler.
MCDisassembler::DecodeStatus
getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes,
uint64_t Address, raw_ostream &VStream,
raw_ostream &CStream) const override;
};

} // namespace llvm

#endif // LLVM_LIB_TARGET_LANAI_DISASSEMBLER_LANAIDISASSEMBLER_H
3 changes: 3 additions & 0 deletions llvm/lib/Target/Lanai/InstPrinter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_llvm_library(LLVMLanaiInstPrinter
LanaiInstPrinter.cpp
)
23 changes: 23 additions & 0 deletions llvm/lib/Target/Lanai/InstPrinter/LLVMBuild.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
;===-- ./lib/Target/Lanai/InstPrinter/LLVMBuild.txt ------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;

[component_0]
type = Library
name = LanaiInstPrinter
parent = Lanai
required_libraries = LanaiInfo MC Support
add_to_library_groups = Lanai
309 changes: 309 additions & 0 deletions llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
//===-- LanaiInstPrinter.cpp - Convert Lanai MCInst to asm syntax ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class prints an Lanai MCInst to a .s file.
//
//===----------------------------------------------------------------------===//

#include "Lanai.h"
#include "LanaiInstPrinter.h"
#include "MCTargetDesc/LanaiMCExpr.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"

using namespace llvm;

#define DEBUG_TYPE "asm-printer"

// Include the auto-generated portion of the assembly writer.
#define PRINT_ALIAS_INSTR
#include "LanaiGenAsmWriter.inc"

void LanaiInstPrinter::printRegName(raw_ostream &Ostream,
unsigned RegNo) const {
Ostream << StringRef(getRegisterName(RegNo)).lower();
}

bool LanaiInstPrinter::printInst(const MCInst *MI, raw_ostream &Ostream,
StringRef Alias, unsigned OpNo0,
unsigned OpNo1) {
Ostream << "\t" << Alias << " ";
printOperand(MI, OpNo0, Ostream);
Ostream << ", ";
printOperand(MI, OpNo1, Ostream);
return true;
}

static bool usesGivenOffset(const MCInst *MI, int AddOffset) {
unsigned AluCode = MI->getOperand(3).getImm();
return LPAC::encodeLanaiAluCode(AluCode) == LPAC::ADD &&
(MI->getOperand(2).getImm() == AddOffset ||
MI->getOperand(2).getImm() == -AddOffset);
}

static bool isPreIncrementForm(const MCInst *MI, int AddOffset) {
unsigned AluCode = MI->getOperand(3).getImm();
return LPAC::isPreOp(AluCode) && usesGivenOffset(MI, AddOffset);
}

static bool isPostIncrementForm(const MCInst *MI, int AddOffset) {
unsigned AluCode = MI->getOperand(3).getImm();
return LPAC::isPostOp(AluCode) && usesGivenOffset(MI, AddOffset);
}

static StringRef decIncOperator(const MCInst *MI) {
if (MI->getOperand(2).getImm() < 0)
return "--";
return "++";
}

bool LanaiInstPrinter::printMemoryLoadIncrement(const MCInst *MI,
raw_ostream &Ostream,
StringRef Opcode,
int AddOffset) {
if (isPreIncrementForm(MI, AddOffset)) {
Ostream << "\t" << Opcode << "\t[" << decIncOperator(MI) << "%"
<< getRegisterName(MI->getOperand(1).getReg()) << "], %"
<< getRegisterName(MI->getOperand(0).getReg());
return true;
}
if (isPostIncrementForm(MI, AddOffset)) {
Ostream << "\t" << Opcode << "\t[%"
<< getRegisterName(MI->getOperand(1).getReg()) << decIncOperator(MI)
<< "], %" << getRegisterName(MI->getOperand(0).getReg());
return true;
}
return false;
}

bool LanaiInstPrinter::printMemoryStoreIncrement(const MCInst *MI,
raw_ostream &Ostream,
StringRef Opcode,
int AddOffset) {
if (isPreIncrementForm(MI, AddOffset)) {
Ostream << "\t" << Opcode << "\t%"
<< getRegisterName(MI->getOperand(0).getReg()) << ", ["
<< decIncOperator(MI) << "%"
<< getRegisterName(MI->getOperand(1).getReg()) << "]";
return true;
}
if (isPostIncrementForm(MI, AddOffset)) {
Ostream << "\t" << Opcode << "\t%"
<< getRegisterName(MI->getOperand(0).getReg()) << ", [%"
<< getRegisterName(MI->getOperand(1).getReg()) << decIncOperator(MI)
<< "]";
return true;
}
return false;
}

bool LanaiInstPrinter::printAlias(const MCInst *MI, raw_ostream &Ostream) {
switch (MI->getOpcode()) {
case Lanai::LDW_RI:
// ld 4[*%rN], %rX => ld [++imm], %rX
// ld -4[*%rN], %rX => ld [--imm], %rX
// ld 4[%rN*], %rX => ld [imm++], %rX
// ld -4[%rN*], %rX => ld [imm--], %rX
return printMemoryLoadIncrement(MI, Ostream, "ld", 4);
case Lanai::LDHs_RI:
return printMemoryLoadIncrement(MI, Ostream, "ld.h", 2);
case Lanai::LDHz_RI:
return printMemoryLoadIncrement(MI, Ostream, "uld.h", 2);
case Lanai::LDBs_RI:
return printMemoryLoadIncrement(MI, Ostream, "ld.b", 1);
case Lanai::LDBz_RI:
return printMemoryLoadIncrement(MI, Ostream, "uld.b", 1);
case Lanai::SW_RI:
// st %rX, 4[*%rN] => st %rX, [++imm]
// st %rX, -4[*%rN] => st %rX, [--imm]
// st %rX, 4[%rN*] => st %rX, [imm++]
// st %rX, -4[%rN*] => st %rX, [imm--]
return printMemoryStoreIncrement(MI, Ostream, "st", 4);
case Lanai::STH_RI:
return printMemoryStoreIncrement(MI, Ostream, "st.h", 2);
case Lanai::STB_RI:
return printMemoryStoreIncrement(MI, Ostream, "st.b", 1);
default:
return false;
}
}

void LanaiInstPrinter::printInst(const MCInst *MI, raw_ostream &Ostream,
StringRef Annotation,
const MCSubtargetInfo &STI) {
if (!printAlias(MI, Ostream) && !printAliasInstr(MI, Ostream))
printInstruction(MI, Ostream);
printAnnotation(Ostream, Annotation);
}

static void printExpr(const MCAsmInfo &MAI, const MCExpr &Expr,
raw_ostream &Ostream) {
const MCExpr *SRE;

if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(&Expr))
SRE = dyn_cast<LanaiMCExpr>(BE->getLHS());
else if (isa<LanaiMCExpr>(&Expr)) {
SRE = dyn_cast<LanaiMCExpr>(&Expr);
} else {
SRE = dyn_cast<MCSymbolRefExpr>(&Expr);
}
assert(SRE && "Unexpected MCExpr type.");

SRE->print(Ostream, &MAI);
}

void LanaiInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &Ostream,
const char *Modifier) {
assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isReg())
Ostream << "%" << getRegisterName(Op.getReg());
else if (Op.isImm())
Ostream << formatHex(Op.getImm());
else {
assert(Op.isExpr() && "Expected an expression");
printExpr(MAI, *Op.getExpr(), Ostream);
}
}

void LanaiInstPrinter::printMemImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &Ostream) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isImm()) {
Ostream << '[' << formatHex(Op.getImm()) << ']';
} else {
// Symbolic operand will be lowered to immediate value by linker
assert(Op.isExpr() && "Expected an expression");
Ostream << '[';
printExpr(MAI, *Op.getExpr(), Ostream);
Ostream << ']';
}
}

void LanaiInstPrinter::printHi16ImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &Ostream) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isImm()) {
Ostream << formatHex(Op.getImm() << 16);
} else {
// Symbolic operand will be lowered to immediate value by linker
assert(Op.isExpr() && "Expected an expression");
printExpr(MAI, *Op.getExpr(), Ostream);
}
}

void LanaiInstPrinter::printHi16AndImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &Ostream) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isImm()) {
Ostream << formatHex((Op.getImm() << 16) | 0xffff);
} else {
// Symbolic operand will be lowered to immediate value by linker
assert(Op.isExpr() && "Expected an expression");
printExpr(MAI, *Op.getExpr(), Ostream);
}
}

void LanaiInstPrinter::printLo16AndImmOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &Ostream) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isImm()) {
Ostream << formatHex(0xffff0000 | Op.getImm());
} else {
// Symbolic operand will be lowered to immediate value by linker
assert(Op.isExpr() && "Expected an expression");
printExpr(MAI, *Op.getExpr(), Ostream);
}
}

static void printMemoryBaseRegister(raw_ostream &Ostream, const unsigned AluCode,
const MCOperand &RegOp) {
assert(RegOp.isReg() && "Register operand expected");
Ostream << "[";
if (LPAC::isPreOp(AluCode))
Ostream << "*";
Ostream << "%" << LanaiInstPrinter::getRegisterName(RegOp.getReg());
if (LPAC::isPostOp(AluCode))
Ostream << "*";
Ostream << "]";
}

template <unsigned SizeInBits>
static void printMemoryImmediateOffset(const MCAsmInfo &MAI,
const MCOperand &OffsetOp,
raw_ostream &Ostream) {
assert((OffsetOp.isImm() || OffsetOp.isExpr()) && "Immediate expected");
if (OffsetOp.isImm()) {
assert(isInt<SizeInBits>(OffsetOp.getImm()) && "Constant value truncated");
Ostream << OffsetOp.getImm();
} else
printExpr(MAI, *OffsetOp.getExpr(), Ostream);
}

void LanaiInstPrinter::printMemRiOperand(const MCInst *MI, int OpNo,
raw_ostream &Ostream,
const char *Modifier) {
const MCOperand &RegOp = MI->getOperand(OpNo);
const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
const MCOperand &AluOp = MI->getOperand(OpNo + 2);
const unsigned AluCode = AluOp.getImm();

// Offset
printMemoryImmediateOffset<16>(MAI, OffsetOp, Ostream);

// Register
printMemoryBaseRegister(Ostream, AluCode, RegOp);
}

void LanaiInstPrinter::printMemRrOperand(const MCInst *MI, int OpNo,
raw_ostream &Ostream,
const char *Modifier) {
const MCOperand &RegOp = MI->getOperand(OpNo);
const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
const MCOperand &AluOp = MI->getOperand(OpNo + 2);
const unsigned AluCode = AluOp.getImm();
assert(OffsetOp.isReg() && RegOp.isReg() && "Registers expected.");

// [ Base OP Offset ]
Ostream << "[";
if (LPAC::isPreOp(AluCode))
Ostream << "*";
Ostream << "%" << getRegisterName(RegOp.getReg());
if (LPAC::isPostOp(AluCode))
Ostream << "*";
Ostream << " " << LPAC::lanaiAluCodeToString(AluCode) << " ";
Ostream << "%" << getRegisterName(OffsetOp.getReg());
Ostream << "]";
}

void LanaiInstPrinter::printMemSplsOperand(const MCInst *MI, int OpNo,
raw_ostream &Ostream,
const char *Modifier) {
const MCOperand &RegOp = MI->getOperand(OpNo);
const MCOperand &OffsetOp = MI->getOperand(OpNo + 1);
const MCOperand &AluOp = MI->getOperand(OpNo + 2);
const unsigned AluCode = AluOp.getImm();

// Offset
printMemoryImmediateOffset<10>(MAI, OffsetOp, Ostream);

// Register
printMemoryBaseRegister(Ostream, AluCode, RegOp);
}

void LanaiInstPrinter::printCCOperand(const MCInst *MI, int OpNo,
raw_ostream &Ostream) {
const int CC = static_cast<const int>(MI->getOperand(OpNo).getImm());
Ostream << lanaiCondCodeToString(static_cast<LPCC::CondCode>(CC));
}
64 changes: 64 additions & 0 deletions llvm/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//= LanaiInstPrinter.h - Convert Lanai MCInst to asm syntax -------*- C++ -*--//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class prints a Lanai MCInst to a .s file.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H
#define LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H

#include "llvm/MC/MCInstPrinter.h"

namespace llvm {
class MCOperand;

class LanaiInstPrinter : public MCInstPrinter {
public:
LanaiInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
const MCRegisterInfo &MRI)
: MCInstPrinter(MAI, MII, MRI) {}

void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
const MCSubtargetInfo &STI) override;
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O,
const char *Modifier = 0);
void printMemRiOperand(const MCInst *MI, int OpNo, raw_ostream &O,
const char *Modifier = 0);
void printMemRrOperand(const MCInst *MI, int OpNo, raw_ostream &O,
const char *Modifier = 0);
void printMemSplsOperand(const MCInst *MI, int OpNo, raw_ostream &O,
const char *Modifier = 0);
void printCCOperand(const MCInst *MI, int OpNo, raw_ostream &O);
void printAluOperand(const MCInst *MI, int OpNo, raw_ostream &O);
void printHi16ImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printHi16AndImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printLo16AndImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);
void printMemImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O);

// Autogenerated by tblgen.
void printInstruction(const MCInst *MI, raw_ostream &O);
bool printAliasInstr(const MCInst *MI, raw_ostream &OS);
void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx,
unsigned PrintMethodIdx, raw_ostream &O);
static const char *getRegisterName(unsigned RegNo);
void printRegName(raw_ostream &OS, unsigned RegNo) const override;

private:
bool printAlias(const MCInst *MI, raw_ostream &Ostream);
bool printInst(const MCInst *MI, raw_ostream &Ostream, StringRef Alias,
unsigned OpNo0, unsigned OpnNo1);
bool printMemoryLoadIncrement(const MCInst *MI, raw_ostream &Ostream,
StringRef Opcode, int AddOffset);
bool printMemoryStoreIncrement(const MCInst *MI, raw_ostream &Ostream,
StringRef Opcode, int AddOffset);
};
} // namespace llvm

#endif // LLVM_LIB_TARGET_LANAI_INSTPRINTER_LANAIINSTPRINTER_H
45 changes: 45 additions & 0 deletions llvm/lib/Target/Lanai/LLVMBuild.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
;===- ./lib/Target/Lanai/LLVMBuild.txt -------------------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;

[common]
subdirectories = AsmParser Disassembler InstPrinter MCTargetDesc TargetInfo

[component_0]
type = TargetGroup
name = Lanai
parent = Target
has_asmprinter = 1

[component_1]
type = Library
name = LanaiCodeGen
parent = Lanai
required_libraries =
Analysis
AsmPrinter
CodeGen
Core
LanaiAsmParser
LanaiMCTargetDesc
LanaiInfo
LanaiInstPrinter
MC
SelectionDAG
Support
Target
TransformUtils
add_to_library_groups = Lanai
51 changes: 51 additions & 0 deletions llvm/lib/Target/Lanai/Lanai.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//===-- Lanai.h - Top-level interface for Lanai representation --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the entry points for global functions defined in the LLVM
// Lanai back-end.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_LANAI_LANAI_H
#define LLVM_LIB_TARGET_LANAI_LANAI_H

#include "LanaiAluCode.h"
#include "LanaiCondCode.h"
#include "MCTargetDesc/LanaiBaseInfo.h"
#include "MCTargetDesc/LanaiMCTargetDesc.h"
#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/Target/TargetMachine.h"

namespace llvm {
class FunctionPass;
class LanaiTargetMachine;
class MachineFunctionPass;
class TargetMachine;
class formatted_raw_ostream;

// createLanaiISelDag - This pass converts a legalized DAG into a
// Lanai-specific DAG, ready for instruction scheduling.
FunctionPass *createLanaiISelDag(LanaiTargetMachine &TM);

// createLanaiDelaySlotFillerPass - This pass fills delay slots
// with useful instructions or nop's
FunctionPass *createLanaiDelaySlotFillerPass(const LanaiTargetMachine &TM);

// createLanaiMemAluCombinerPass - This pass combines loads/stores and
// arithmetic operations.
FunctionPass *createLanaiMemAluCombinerPass();

// createLanaiSetflagAluCombinerPass - This pass combines SET_FLAG and ALU
// operations.
FunctionPass *createLanaiSetflagAluCombinerPass();

extern Target TheLanaiTarget;
} // namespace llvm

#endif // LLVM_LIB_TARGET_LANAI_LANAI_H
47 changes: 47 additions & 0 deletions llvm/lib/Target/Lanai/Lanai.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===- Lanai.td - Describe the Lanai Target Machine --------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// Target-independent interfaces which we are implementing
//===----------------------------------------------------------------------===//

include "llvm/Target/Target.td"

//===----------------------------------------------------------------------===//
// Register File, Calling Conv, Instruction Descriptions
//===----------------------------------------------------------------------===//

include "LanaiSchedule.td"
include "LanaiRegisterInfo.td"
include "LanaiCallingConv.td"
include "LanaiInstrInfo.td"

def LanaiInstrInfo : InstrInfo;

//===----------------------------------------------------------------------===//
// Lanai processors supported.
//===----------------------------------------------------------------------===//

def : ProcessorModel<"generic", LanaiSchedModel, []>;
def : ProcessorModel<"v11", LanaiSchedModel, []>;

def LanaiInstPrinter : AsmWriter {
string AsmWriterClassName = "InstPrinter";
bit isMCAsmWriter = 1;
}

//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
//===----------------------------------------------------------------------===//

def Lanai : Target {
// Pull in Instruction Info:
let InstructionSet = LanaiInstrInfo;
let AssemblyWriters = [LanaiInstPrinter];
}
148 changes: 148 additions & 0 deletions llvm/lib/Target/Lanai/LanaiAluCode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//===-- LanaiAluCode.h - ALU operator encoding ----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The encoding for ALU operators used in RM and RRM operands
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_LANAI_LANAIALUCODE_H
#define LLVM_LIB_TARGET_LANAI_LANAIALUCODE_H

#include "llvm/ADT/StringSwitch.h"
#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/Support/ErrorHandling.h"

namespace llvm {
namespace LPAC {
enum AluCode {
ADD = 0x00,
ADDC = 0x01,
SUB = 0x02,
SUBB = 0x03,
AND = 0x04,
OR = 0x05,
XOR = 0x06,
SPECIAL = 0x07,

// Shift instructions are treated as SPECIAL when encoding the machine
// instruction, but kept distinct until lowering. The constant values are
// chosen to ease lowering.
SHL = 0x17,
SRL = 0x27,
SRA = 0x37,

// Indicates an unknown/unsupported operator
UNKNOWN = 0xFF,
};

// Bits indicating post- and pre-operators should be tested and set using Is*
// and Make* utility functions
constexpr int Lanai_PRE_OP = 0x40;
constexpr int Lanai_POST_OP = 0x80;

inline static unsigned encodeLanaiAluCode(unsigned AluOp) {
unsigned const OP_ENCODING_MASK = 0x07;
return AluOp & OP_ENCODING_MASK;
}

inline static unsigned getAluOp(unsigned AluOp) {
unsigned const ALU_MASK = 0x3F;
return AluOp & ALU_MASK;
}

inline static bool isPreOp(unsigned AluOp) { return AluOp & Lanai_PRE_OP; }

inline static bool isPostOp(unsigned AluOp) { return AluOp & Lanai_POST_OP; }

inline static unsigned makePreOp(unsigned AluOp) {
assert(!isPostOp(AluOp) && "Operator can't be a post- and pre-op");
return AluOp | Lanai_PRE_OP;
}

inline static unsigned makePostOp(unsigned AluOp) {
assert(!isPreOp(AluOp) && "Operator can't be a post- and pre-op");
return AluOp | Lanai_POST_OP;
}

inline static bool modifiesOp(unsigned AluOp) {
return isPreOp(AluOp) | isPostOp(AluOp);
}

inline static const char *lanaiAluCodeToString(unsigned AluOp) {
switch (getAluOp(AluOp)) {
case ADD:
return "add";
case ADDC:
return "addc";
case SUB:
return "sub";
case SUBB:
return "subb";
case AND:
return "and";
case OR:
return "or";
case XOR:
return "xor";
case SHL:
return "sh";
case SRL:
return "sh";
case SRA:
return "sha";
default:
llvm_unreachable("Invalid ALU code.");
}
}

inline static AluCode stringToLanaiAluCode(StringRef S) {
return StringSwitch<AluCode>(S)
.Case("add", ADD)
.Case("addc", ADDC)
.Case("sub", SUB)
.Case("subb", SUBB)
.Case("and", AND)
.Case("or", OR)
.Case("xor", XOR)
.Case("sh", SHL)
.Case("srl", SRL)
.Case("sha", SRA)
.Default(UNKNOWN);
}

inline static AluCode isdToLanaiAluCode(ISD::NodeType Node_type) {
switch (Node_type) {
case ISD::ADD:
return AluCode::ADD;
case ISD::ADDE:
return AluCode::ADDC;
case ISD::SUB:
return AluCode::SUB;
case ISD::SUBE:
return AluCode::SUBB;
case ISD::AND:
return AluCode::AND;
case ISD::OR:
return AluCode::OR;
case ISD::XOR:
return AluCode::XOR;
case ISD::SHL:
return AluCode::SHL;
case ISD::SRL:
return AluCode::SRL;
case ISD::SRA:
return AluCode::SRA;
default:
return AluCode::UNKNOWN;
}
}
} // namespace LPAC
} // namespace llvm

#endif // LLVM_LIB_TARGET_LANAI_LANAIALUCODE_H
252 changes: 252 additions & 0 deletions llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
//===-- LanaiAsmPrinter.cpp - Lanai LLVM assembly writer ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a printer that converts from our internal representation
// of machine-dependent LLVM code to the Lanai assembly language.
//
//===----------------------------------------------------------------------===//

#include "Lanai.h"
#include "InstPrinter/LanaiInstPrinter.h"
#include "LanaiInstrInfo.h"
#include "LanaiMCInstLower.h"
#include "LanaiTargetMachine.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"

#define DEBUG_TYPE "asm-printer"

using namespace llvm;

namespace {
class LanaiAsmPrinter : public AsmPrinter {
public:
explicit LanaiAsmPrinter(TargetMachine &TM,
std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)) {}

const char *getPassName() const override { return "Lanai Assembly Printer"; }

void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O,
const char *Modifier = 0);
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O) override;
void EmitInstruction(const MachineInstr *MI) override;
bool isBlockOnlyReachableByFallthrough(
const MachineBasicBlock *MBB) const override;

private:
void customEmitInstruction(const MachineInstr *MI);
void emitCallInstruction(const MachineInstr *MI);
};
} // end of anonymous namespace

void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
raw_ostream &O, const char *Modifier) {
const MachineOperand &MO = MI->getOperand(OpNum);
unsigned TF = MO.getTargetFlags();

switch (MO.getType()) {
case MachineOperand::MO_Register:
O << LanaiInstPrinter::getRegisterName(MO.getReg());
break;

case MachineOperand::MO_Immediate:
O << MO.getImm();
break;

case MachineOperand::MO_MachineBasicBlock:
O << *MO.getMBB()->getSymbol();
break;

case MachineOperand::MO_GlobalAddress:
if (TF == LanaiII::MO_PLT)
O << "plt(" << *getSymbol(MO.getGlobal()) << ")";
else
O << *getSymbol(MO.getGlobal());
break;

case MachineOperand::MO_BlockAddress: {
MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
O << BA->getName();
break;
}

case MachineOperand::MO_ExternalSymbol:
if (TF == LanaiII::MO_PLT)
O << "plt(" << *GetExternalSymbolSymbol(MO.getSymbolName()) << ")";
else
O << *GetExternalSymbolSymbol(MO.getSymbolName());
break;

case MachineOperand::MO_JumpTableIndex:
O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_'
<< MO.getIndex();
break;

case MachineOperand::MO_ConstantPoolIndex:
O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_'
<< MO.getIndex();
return;

default:
llvm_unreachable("<unknown operand type>");
}
}

// PrintAsmOperand - Print out an operand for an inline asm expression.
//
bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode, raw_ostream &O) {
// Does this asm operand have a single letter operand modifier?
if (ExtraCode && ExtraCode[0]) {
if (ExtraCode[1])
return true; // Unknown modifier.

switch (ExtraCode[0]) {
// The highest-numbered register of a pair.
case 'H': {
if (OpNo == 0)
return true;
const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);
if (!FlagsOP.isImm())
return true;
unsigned Flags = FlagsOP.getImm();
unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
if (NumVals != 2)
return true;
unsigned RegOp = OpNo + 1;
if (RegOp >= MI->getNumOperands())
return true;
const MachineOperand &MO = MI->getOperand(RegOp);
if (!MO.isReg())
return true;
unsigned Reg = MO.getReg();
O << LanaiInstPrinter::getRegisterName(Reg);
return false;
}
default:
return true; // Unknown modifier.
}
}
printOperand(MI, OpNo, O);
return false;
}

//===----------------------------------------------------------------------===//
void LanaiAsmPrinter::emitCallInstruction(const MachineInstr *MI) {
assert((MI->getOpcode() == Lanai::CALL || MI->getOpcode() == Lanai::CALLR) &&
"Unsupported call function");

LanaiMCInstLower MCInstLowering(OutContext, *Mang, *this);
MCSubtargetInfo STI = getSubtargetInfo();
// Insert save rca instruction immediately before the call.
// TODO: We should generate a pc-relative mov instruction here instead
// of pc + 16 (should be mov .+16 %rca).
OutStreamer->EmitInstruction(MCInstBuilder(Lanai::ADD_I_LO)
.addReg(Lanai::RCA)
.addReg(Lanai::PC)
.addImm(16),
STI);

// Push rca onto the stack.
// st %rca, [--%sp]
OutStreamer->EmitInstruction(MCInstBuilder(Lanai::SW_RI)
.addReg(Lanai::RCA)
.addReg(Lanai::SP)
.addImm(-4)
.addImm(LPAC::makePreOp(LPAC::ADD)),
STI);

// Lower the call instruction.
if (MI->getOpcode() == Lanai::CALL) {
MCInst TmpInst;
MCInstLowering.Lower(MI, TmpInst);
TmpInst.setOpcode(Lanai::BT);
OutStreamer->EmitInstruction(TmpInst, STI);
} else {
OutStreamer->EmitInstruction(MCInstBuilder(Lanai::ADD_R)
.addReg(Lanai::PC)
.addReg(MI->getOperand(0).getReg())
.addReg(Lanai::R0)
.addImm(LPCC::ICC_T),
STI);
}
}

void LanaiAsmPrinter::customEmitInstruction(const MachineInstr *MI) {
LanaiMCInstLower MCInstLowering(OutContext, *Mang, *this);
MCSubtargetInfo STI = getSubtargetInfo();
MCInst TmpInst;
MCInstLowering.Lower(MI, TmpInst);
OutStreamer->EmitInstruction(TmpInst, STI);
}

void LanaiAsmPrinter::EmitInstruction(const MachineInstr *MI) {
MachineBasicBlock::const_instr_iterator I = MI->getIterator();
MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();

do {
if (I->isCall()) {
emitCallInstruction(&*I);
continue;
}

customEmitInstruction(&*I);
} while ((++I != E) && I->isInsideBundle());
}

// isBlockOnlyReachableByFallthough - Return true if the basic block has
// exactly one predecessor and the control transfer mechanism between
// the predecessor and this block is a fall-through.
// FIXME: could the overridden cases be handled in AnalyzeBranch?
bool LanaiAsmPrinter::isBlockOnlyReachableByFallthrough(
const MachineBasicBlock *MBB) const {
// The predecessor has to be immediately before this block.
const MachineBasicBlock *Pred = *MBB->pred_begin();

// If the predecessor is a switch statement, assume a jump table
// implementation, so it is not a fall through.
if (const BasicBlock *B = Pred->getBasicBlock())
if (isa<SwitchInst>(B->getTerminator()))
return false;

// Check default implementation
if (!AsmPrinter::isBlockOnlyReachableByFallthrough(MBB))
return false;

// Otherwise, check the last instruction.
// Check if the last terminator is an unconditional branch.
MachineBasicBlock::const_iterator I = Pred->end();
while (I != Pred->begin() && !(--I)->isTerminator()) {
}

return !I->isBarrier();
}

// Force static initialization.
extern "C" void LLVMInitializeLanaiAsmPrinter() {
RegisterAsmPrinter<LanaiAsmPrinter> X(TheLanaiTarget);
}
50 changes: 50 additions & 0 deletions llvm/lib/Target/Lanai/LanaiCallingConv.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//===- LanaiCallingConv.td - Calling Conventions Lanai -------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This describes the calling conventions for the Lanai architectures.
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// Return Value Calling Conventions
//===----------------------------------------------------------------------===//

// Lanai 32-bit C Calling convention.
def CC_Lanai32 : CallingConv<[
// Promote i8/i16 args to i32
CCIfType<[i8, i16], CCPromoteToType<i32>>,

// Put argument in registers if marked 'inreg' and not a vararg call.
CCIfNotVarArg<CCIfInReg<CCIfType<[i32],
CCAssignToReg<[R6, R7, R18, R19]>>>>,

// Otherwise they are assigned to the stack in 4-byte aligned units.
CCAssignToStack<4, 4>
]>;

// Lanai 32-bit Fast Calling convention.
def CC_Lanai32_Fast : CallingConv<[
// Promote i8/i16 args to i32
CCIfType<[ i8, i16 ], CCPromoteToType<i32>>,

// Put arguments in registers.
CCIfNotVarArg<CCIfType<[i32], CCAssignToReg<[ R6, R7, R18, R19 ]>>>,

// Otherwise they are assigned to the stack in 4-byte aligned units.
CCAssignToStack<4, 4>
]>;

// Lanai 32-bit C return-value convention.
def RetCC_Lanai32 : CallingConv<[
// Specify two registers to allow returning 64-bit results that have already
// been lowered to 2 32-bit values.
CCIfType<[i32], CCAssignToReg<[RV, R9]>>
]>;

def CSR: CalleeSavedRegs<(add)>;
100 changes: 100 additions & 0 deletions llvm/lib/Target/Lanai/LanaiCondCode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// The encoding used for conditional codes used in BR instructions

#ifndef LLVM_LIB_TARGET_LANAI_LANAICONDCODE_H
#define LLVM_LIB_TARGET_LANAI_LANAICONDCODE_H

#include "llvm/ADT/StringSwitch.h"

namespace llvm {
namespace LPCC {
enum CondCode {
ICC_T = 0, // true
ICC_F = 1, // false
ICC_HI = 2, // high
ICC_UGT = 2, // unsigned greater than
ICC_LS = 3, // low or same
ICC_ULE = 3, // unsigned less than or equal
ICC_CC = 4, // carry cleared
ICC_ULT = 4, // unsigned less than
ICC_CS = 5, // carry set
ICC_UGE = 5, // unsigned greater than or equal
ICC_NE = 6, // not equal
ICC_EQ = 7, // equal
ICC_VC = 8, // oVerflow cleared
ICC_VS = 9, // oVerflow set
ICC_PL = 10, // plus
ICC_MI = 11, // minus
ICC_GE = 12, // greater than or equal
ICC_LT = 13, // less than
ICC_GT = 14, // greater than
ICC_LE = 15, // less than or equal
UNKNOWN
};

inline static StringRef lanaiCondCodeToString(LPCC::CondCode CC) {
switch (CC) {
case LPCC::ICC_T:
return "t"; // true
case LPCC::ICC_F:
return "f"; // false
case LPCC::ICC_NE:
return "ne"; // not equal
case LPCC::ICC_EQ:
return "eq"; // equal
case LPCC::ICC_VC:
return "vc"; // oVerflow cleared
case LPCC::ICC_VS:
return "vs"; // oVerflow set
case LPCC::ICC_PL:
return "pl"; // plus
case LPCC::ICC_MI:
return "mi"; // minus
case LPCC::ICC_GE:
return "ge"; // greater than or equal
case LPCC::ICC_LT:
return "lt"; // less than
case LPCC::ICC_GT:
return "gt"; // greater than
case LPCC::ICC_LE:
return "le"; // less than or equal
case LPCC::ICC_UGT:
return "ugt"; // high | unsigned greater than
case LPCC::ICC_ULE:
return "ule"; // low or same | unsigned less or equal
case LPCC::ICC_ULT:
return "ult"; // carry cleared | unsigned less than
case LPCC::ICC_UGE:
return "uge"; // carry set | unsigned than or equal
default:
llvm_unreachable("Invalid cond code");
}
}

inline static CondCode suffixToLanaiCondCode(StringRef S) {
return StringSwitch<CondCode>(S)
.EndsWith("f", LPCC::ICC_F)
.EndsWith("hi", LPCC::ICC_HI)
.EndsWith("ugt", LPCC::ICC_UGT)
.EndsWith("ls", LPCC::ICC_LS)
.EndsWith("ule", LPCC::ICC_ULE)
.EndsWith("cc", LPCC::ICC_CC)
.EndsWith("ult", LPCC::ICC_ULT)
.EndsWith("cs", LPCC::ICC_CS)
.EndsWith("uge", LPCC::ICC_UGE)
.EndsWith("ne", LPCC::ICC_NE)
.EndsWith("eq", LPCC::ICC_EQ)
.EndsWith("vc", LPCC::ICC_VC)
.EndsWith("vs", LPCC::ICC_VS)
.EndsWith("pl", LPCC::ICC_PL)
.EndsWith("mi", LPCC::ICC_MI)
.EndsWith("ge", LPCC::ICC_GE)
.EndsWith("lt", LPCC::ICC_LT)
.EndsWith("gt", LPCC::ICC_GT)
.EndsWith("le", LPCC::ICC_LE)
.EndsWith("t", LPCC::ICC_T) // Has to be after others with suffix t
.Default(LPCC::UNKNOWN);
}
} // namespace LPCC
} // namespace llvm

#endif // LLVM_LIB_TARGET_LANAI_LANAICONDCODE_H
250 changes: 250 additions & 0 deletions llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
//===-- LanaiDelaySlotFiller.cpp - Lanai delay slot filler ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Simple pass to fills delay slots with useful instructions.
//
//===----------------------------------------------------------------------===//

#include "Lanai.h"
#include "LanaiTargetMachine.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetInstrInfo.h"

using namespace llvm;

#define DEBUG_TYPE "delay-slot-filler"

STATISTIC(FilledSlots, "Number of delay slots filled");

static cl::opt<bool>
NopDelaySlotFiller("lanai-nop-delay-filler", cl::init(false),
cl::desc("Fill Lanai delay slots with NOPs."),
cl::Hidden);

namespace {
struct Filler : public MachineFunctionPass {
// Target machine description which we query for reg. names, data
// layout, etc.
const TargetInstrInfo *TII;
const TargetRegisterInfo *TRI;
MachineBasicBlock::instr_iterator LastFiller;

static char ID;
explicit Filler() : MachineFunctionPass(ID) {}

const char *getPassName() const override { return "Lanai Delay Slot Filler"; }

bool runOnMachineBasicBlock(MachineBasicBlock &MBB);

bool runOnMachineFunction(MachineFunction &MF) override {
const LanaiSubtarget &Subtarget = MF.getSubtarget<LanaiSubtarget>();
TII = Subtarget.getInstrInfo();
TRI = Subtarget.getRegisterInfo();

bool Changed = false;
for (MachineFunction::iterator FI = MF.begin(), FE = MF.end(); FI != FE;
++FI)
Changed |= runOnMachineBasicBlock(*FI);
return Changed;
}

void insertDefsUses(MachineBasicBlock::instr_iterator MI,
SmallSet<unsigned, 32> &RegDefs,
SmallSet<unsigned, 32> &RegUses);

bool isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg);

bool delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,
bool &SawStore, SmallSet<unsigned, 32> &RegDefs,
SmallSet<unsigned, 32> &RegUses);

bool findDelayInstr(MachineBasicBlock &MBB,
MachineBasicBlock::instr_iterator Slot,
MachineBasicBlock::instr_iterator &Filler);
};
char Filler::ID = 0;
} // end of anonymous namespace

// createLanaiDelaySlotFillerPass - Returns a pass that fills in delay
// slots in Lanai MachineFunctions
FunctionPass *
llvm::createLanaiDelaySlotFillerPass(const LanaiTargetMachine &tm) {
return new Filler();
}

// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
// There is one or two delay slot per delayed instruction.
bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
bool Changed = false;
LastFiller = MBB.instr_end();

for (MachineBasicBlock::instr_iterator I = MBB.instr_begin();
I != MBB.instr_end(); ++I) {
if (I->getDesc().hasDelaySlot()) {
MachineBasicBlock::instr_iterator InstrWithSlot = I;
MachineBasicBlock::instr_iterator J = I;

// Treat RET specially as it is only instruction with 2 delay slots
// generated while all others generated have 1 delay slot.
if (I->getOpcode() == Lanai::RET) {
// RET is generated as part of epilogue generation and hence we know
// what the two instructions preceding it are and that it is safe to
// insert RET above them.
MachineBasicBlock::reverse_instr_iterator RI(I);
assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() &&
RI->getOperand(0).getReg() == Lanai::FP &&
RI->getOperand(1).isReg() &&
RI->getOperand(1).getReg() == Lanai::FP &&
RI->getOperand(2).isImm() && RI->getOperand(2).getImm() == -8);
++RI;
assert(RI->getOpcode() == Lanai::ADD_I_LO &&
RI->getOperand(0).isReg() &&
RI->getOperand(0).getReg() == Lanai::SP &&
RI->getOperand(1).isReg() &&
RI->getOperand(1).getReg() == Lanai::FP);
++RI;
MachineBasicBlock::instr_iterator FI(RI.base());
MBB.splice(std::next(I), &MBB, FI, I);
FilledSlots += 2;
} else {
if (!NopDelaySlotFiller && findDelayInstr(MBB, I, J)) {
MBB.splice(std::next(I), &MBB, J);
} else {
BuildMI(MBB, std::next(I), DebugLoc(), TII->get(Lanai::NOP));
}
++FilledSlots;
}

Changed = true;
// Record the filler instruction that filled the delay slot.
// The instruction after it will be visited in the next iteration.
LastFiller = ++I;

// Bundle the delay slot filler to InstrWithSlot so that the machine
// verifier doesn't expect this instruction to be a terminator.
MIBundleBuilder(MBB, InstrWithSlot, std::next(LastFiller));
}
}
return Changed;
}

bool Filler::findDelayInstr(MachineBasicBlock &MBB,
MachineBasicBlock::instr_iterator Slot,
MachineBasicBlock::instr_iterator &Filler) {
SmallSet<unsigned, 32> RegDefs;
SmallSet<unsigned, 32> RegUses;

insertDefsUses(Slot, RegDefs, RegUses);

bool SawLoad = false;
bool SawStore = false;

for (MachineBasicBlock::reverse_instr_iterator I(Slot); I != MBB.instr_rend();
++I) {
// skip debug value
if (I->isDebugValue())
continue;

// Convert to forward iterator.
MachineBasicBlock::instr_iterator FI(std::next(I).base());

if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() ||
FI == LastFiller || I->isPseudo())
break;

if (delayHasHazard(FI, SawLoad, SawStore, RegDefs, RegUses)) {
insertDefsUses(FI, RegDefs, RegUses);
continue;
}
Filler = FI;
return true;
}
return false;
}

bool Filler::delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,
bool &SawStore, SmallSet<unsigned, 32> &RegDefs,
SmallSet<unsigned, 32> &RegUses) {
if (MI->isImplicitDef() || MI->isKill())
return true;

// Loads or stores cannot be moved past a store to the delay slot
// and stores cannot be moved past a load.
if (MI->mayLoad()) {
if (SawStore)
return true;
SawLoad = true;
}

if (MI->mayStore()) {
if (SawStore)
return true;
SawStore = true;
if (SawLoad)
return true;
}

assert((!MI->isCall() && !MI->isReturn()) &&
"Cannot put calls or returns in delay slot.");

for (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
const MachineOperand &MO = MI->getOperand(I);
unsigned Reg;

if (!MO.isReg() || !(Reg = MO.getReg()))
continue; // skip

if (MO.isDef()) {
// check whether Reg is defined or used before delay slot.
if (isRegInSet(RegDefs, Reg) || isRegInSet(RegUses, Reg))
return true;
}
if (MO.isUse()) {
// check whether Reg is defined before delay slot.
if (isRegInSet(RegDefs, Reg))
return true;
}
}
return false;
}

// Insert Defs and Uses of MI into the sets RegDefs and RegUses.
void Filler::insertDefsUses(MachineBasicBlock::instr_iterator MI,
SmallSet<unsigned, 32> &RegDefs,
SmallSet<unsigned, 32> &RegUses) {
// If MI is a call or return, just examine the explicit non-variadic operands.
MCInstrDesc MCID = MI->getDesc();
unsigned E = MI->isCall() || MI->isReturn() ? MCID.getNumOperands()
: MI->getNumOperands();
for (unsigned I = 0; I != E; ++I) {
const MachineOperand &MO = MI->getOperand(I);
unsigned Reg;

if (!MO.isReg() || !(Reg = MO.getReg()))
continue;

if (MO.isDef())
RegDefs.insert(Reg);
else if (MO.isUse())
RegUses.insert(Reg);
}
}

// Returns true if the Reg or its alias is in the RegSet.
bool Filler::isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg) {
// Check Reg and all aliased Registers.
for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
if (RegSet.count(*AI))
return true;
return false;
}
220 changes: 220 additions & 0 deletions llvm/lib/Target/Lanai/LanaiFrameLowering.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
//===-- LanaiFrameLowering.cpp - Lanai Frame Information ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Lanai implementation of TargetFrameLowering class.
//
//===----------------------------------------------------------------------===//

#include "LanaiFrameLowering.h"

#include "LanaiInstrInfo.h"
#include "LanaiMachineFunctionInfo.h"
#include "LanaiSubtarget.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Function.h"

using namespace llvm;

// Determines the size of the frame and maximum call frame size.
void LanaiFrameLowering::determineFrameLayout(MachineFunction &MF) const {
MachineFrameInfo *MFI = MF.getFrameInfo();
const LanaiRegisterInfo *LRI = STI.getRegisterInfo();

// Get the number of bytes to allocate from the FrameInfo.
unsigned FrameSize = MFI->getStackSize();

// Get the alignment.
unsigned StackAlign = LRI->needsStackRealignment(MF) ? MFI->getMaxAlignment()
: getStackAlignment();

// Get the maximum call frame size of all the calls.
unsigned MaxCallFrameSize = MFI->getMaxCallFrameSize();

// If we have dynamic alloca then MaxCallFrameSize needs to be aligned so
// that allocations will be aligned.
if (MFI->hasVarSizedObjects())
MaxCallFrameSize = alignTo(MaxCallFrameSize, StackAlign);

// Update maximum call frame size.
MFI->setMaxCallFrameSize(MaxCallFrameSize);

// Include call frame size in total.
if (!(hasReservedCallFrame(MF) && MFI->adjustsStack()))
FrameSize += MaxCallFrameSize;

// Make sure the frame is aligned.
FrameSize = alignTo(FrameSize, StackAlign);

// Update frame info.
MFI->setStackSize(FrameSize);
}

// Iterates through each basic block in a machine function and replaces
// ADJDYNALLOC pseudo instructions with a Lanai:ADDI with the
// maximum call frame size as the immediate.
void LanaiFrameLowering::replaceAdjDynAllocPseudo(MachineFunction &MF) const {
const LanaiInstrInfo &LII =
*static_cast<const LanaiInstrInfo *>(STI.getInstrInfo());
unsigned MaxCallFrameSize = MF.getFrameInfo()->getMaxCallFrameSize();

for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); MBB != E;
++MBB) {
MachineBasicBlock::iterator MBBI = MBB->begin();
while (MBBI != MBB->end()) {
MachineInstr *MI = MBBI++;
if (MI->getOpcode() == Lanai::ADJDYNALLOC) {
DebugLoc DL = MI->getDebugLoc();
unsigned Dst = MI->getOperand(0).getReg();
unsigned Src = MI->getOperand(1).getReg();

BuildMI(*MBB, MI, DL, LII.get(Lanai::ADD_I_LO), Dst)
.addReg(Src)
.addImm(MaxCallFrameSize);
MI->eraseFromParent();
}
}
}
}

// Generates the following sequence for function entry:
// st %fp,-4[*%sp] !push old FP
// add %sp,8,%fp !generate new FP
// sub %sp,0x4,%sp !allocate stack space (as needed)
void LanaiFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");

MachineFrameInfo *MFI = MF.getFrameInfo();
const LanaiInstrInfo &LII =
*static_cast<const LanaiInstrInfo *>(STI.getInstrInfo());
MachineBasicBlock::iterator MBBI = MBB.begin();

// Debug location must be unknown since the first debug location is used
// to determine the end of the prologue.
DebugLoc DL;

// Determine the correct frame layout
determineFrameLayout(MF);

// FIXME: This appears to be overallocating. Needs investigation.
// Get the number of bytes to allocate from the FrameInfo.
unsigned StackSize = MFI->getStackSize();

// Push old FP
// st %fp,-4[*%sp]
BuildMI(MBB, MBBI, DL, LII.get(Lanai::SW_RI))
.addReg(Lanai::FP)
.addReg(Lanai::SP)
.addImm(-4)
.addImm(LPAC::makePreOp(LPAC::ADD))
.setMIFlag(MachineInstr::FrameSetup);

// Generate new FP
// add %sp,8,%fp
BuildMI(MBB, MBBI, DL, LII.get(Lanai::ADD_I_LO), Lanai::FP)
.addReg(Lanai::SP)
.addImm(8)
.setMIFlag(MachineInstr::FrameSetup);

// Allocate space on the stack if needed
// sub %sp,StackSize,%sp
if (StackSize != 0) {
BuildMI(MBB, MBBI, DL, LII.get(Lanai::SUB_I_LO), Lanai::SP)
.addReg(Lanai::SP)
.addImm(StackSize)
.setMIFlag(MachineInstr::FrameSetup);
}

// Replace ADJDYNANALLOC
if (MFI->hasVarSizedObjects())
replaceAdjDynAllocPseudo(MF);
}

void LanaiFrameLowering::eliminateCallFramePseudoInstr(
MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
// Discard ADJCALLSTACKDOWN, ADJCALLSTACKUP instructions.
MBB.erase(I);
}

// The function epilogue should not depend on the current stack pointer!
// It should use the frame pointer only. This is mandatory because
// of alloca; we also take advantage of it to omit stack adjustments
// before returning.
//
// Note that when we go to restore the preserved register values we must
// not try to address their slots by using offsets from the stack pointer.
// That's because the stack pointer may have been moved during the function
// execution due to a call to alloca(). Rather, we must restore all
// preserved registers via offsets from the frame pointer value.
//
// Note also that when the current frame is being "popped" (by adjusting
// the value of the stack pointer) on function exit, we must (for the
// sake of alloca) set the new value of the stack pointer based upon
// the current value of the frame pointer. We can't just add what we
// believe to be the (static) frame size to the stack pointer because
// if we did that, and alloca() had been called during this function,
// we would end up returning *without* having fully deallocated all of
// the space grabbed by alloca. If that happened, and a function
// containing one or more alloca() calls was called over and over again,
// then the stack would grow without limit!
//
// RET is lowered to
// ld -4[%fp],%pc # modify %pc (two delay slots)
// as the return address is in the stack frame and mov to pc is allowed.
// emitEpilogue emits
// mov %fp,%sp # restore the stack pointer
// ld -8[%fp],%fp # restore the caller's frame pointer
// before RET and the delay slot filler will move RET such that these
// instructions execute in the delay slots of the load to PC.
void LanaiFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
const LanaiInstrInfo &LII =
*static_cast<const LanaiInstrInfo *>(STI.getInstrInfo());
DebugLoc DL = MBBI->getDebugLoc();

// Restore the stack pointer using the callee's frame pointer value.
BuildMI(MBB, MBBI, DL, LII.get(Lanai::ADD_I_LO), Lanai::SP)
.addReg(Lanai::FP)
.addImm(0);

// Restore the frame pointer from the stack.
BuildMI(MBB, MBBI, DL, LII.get(Lanai::LDW_RI), Lanai::FP)
.addReg(Lanai::FP)
.addImm(-8)
.addImm(LPAC::ADD);
}

void LanaiFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);

MachineFrameInfo *MFI = MF.getFrameInfo();
const LanaiRegisterInfo *LRI =
static_cast<const LanaiRegisterInfo *>(STI.getRegisterInfo());
int Offset = -4;

// Reserve 4 bytes for the saved RCA
MFI->CreateFixedObject(4, Offset, true);
Offset -= 4;

// Reserve 4 bytes for the saved FP
MFI->CreateFixedObject(4, Offset, true);
Offset -= 4;

if (LRI->hasBasePointer(MF)) {
MFI->CreateFixedObject(4, Offset, true);
SavedRegs.reset(LRI->getBaseRegister());
}
}
57 changes: 57 additions & 0 deletions llvm/lib/Target/Lanai/LanaiFrameLowering.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//===-- LanaiFrameLowering.h - Define frame lowering for Lanai --*- C++-*--===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class implements Lanai-specific bits of TargetFrameLowering class.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_LANAI_LANAIFRAMELOWERING_H
#define LLVM_LIB_TARGET_LANAI_LANAIFRAMELOWERING_H

#include "Lanai.h"
#include "llvm/Target/TargetFrameLowering.h"

namespace llvm {

class BitVector;
class LanaiSubtarget;

class LanaiFrameLowering : public TargetFrameLowering {
private:
void determineFrameLayout(MachineFunction &MF) const;
void replaceAdjDynAllocPseudo(MachineFunction &MF) const;

protected:
const LanaiSubtarget &STI;

public:
explicit LanaiFrameLowering(const LanaiSubtarget &Subtarget)
: TargetFrameLowering(StackGrowsDown,
/*StackAlignment=*/8,
/*LocalAreaOffset=*/0),
STI(Subtarget) {}

// emitProlog/emitEpilog - These methods insert prolog and epilog code into
// the function.
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;

void
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const override;

bool hasFP(const MachineFunction &MF) const override { return true; }

void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
RegScavenger *RS = nullptr) const override;
};

} // namespace llvm

#endif // LLVM_LIB_TARGET_LANAI_LANAIFRAMELOWERING_H
325 changes: 325 additions & 0 deletions llvm/lib/Target/Lanai/LanaiISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
//===-- LanaiISelDAGToDAG.cpp - A dag to dag inst selector for Lanai ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an instruction selector for the Lanai target.
//
//===----------------------------------------------------------------------===//

#include "Lanai.h"
#include "LanaiMachineFunctionInfo.h"
#include "LanaiRegisterInfo.h"
#include "LanaiSubtarget.h"
#include "LanaiTargetMachine.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"

using namespace llvm;

#define DEBUG_TYPE "lanai-isel"

//===----------------------------------------------------------------------===//
// Instruction Selector Implementation
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// LanaiDAGToDAGISel - Lanai specific code to select Lanai machine
// instructions for SelectionDAG operations.
//===----------------------------------------------------------------------===//
namespace {

class LanaiDAGToDAGISel : public SelectionDAGISel {
public:
explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine)
: SelectionDAGISel(TargetMachine) {}

bool runOnMachineFunction(MachineFunction &MF) override {
return SelectionDAGISel::runOnMachineFunction(MF);
}

// Pass Name
const char *getPassName() const override {
return "Lanai DAG->DAG Pattern Instruction Selection";
}

bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
std::vector<SDValue> &OutOps) override;

private:
// Include the pieces autogenerated from the target description.
#include "LanaiGenDAGISel.inc"

// Instruction Selection not handled by the auto-generated tablgen
SDNode *Select(SDNode *N) override;

// Support functions for the opcodes of Instruction Selection
// not handled by the auto-generated tablgen
SDNode *selectFrameIndex(SDNode *N);

// Complex Pattern for address selection.
bool selectAddrRi(SDValue Addr, SDValue &Base, SDValue &Offset,
SDValue &AluOp);
bool selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2, SDValue &AluOp);
bool selectAddrSls(SDValue Addr, SDValue &Offset);
bool selectAddrSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
SDValue &AluOp);

// getI32Imm - Return a target constant with the specified value, of type i32.
inline SDValue getI32Imm(unsigned Imm, SDLoc DL) {
return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
}

private:
bool selectAddrRiSpls(SDValue Addr, SDValue &Base, SDValue &Offset,
SDValue &AluOp, bool RiMode);
};

bool canBeRepresentedAsSls(const ConstantSDNode &CN) {
// Fits in 21-bit signed immediate and two low-order bits are zero.
return isInt<21>(CN.getSExtValue()) && ((CN.getSExtValue() & 0x3) == 0);
}

} // namespace

// Helper functions for ComplexPattern used on LanaiInstrInfo
// Used on Lanai Load/Store instructions.
bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr, SDValue &Offset) {
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
SDLoc DL(Addr);
// Loading from a constant address.
if (canBeRepresentedAsSls(*CN)) {
int32_t Imm = CN->getSExtValue();
Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
return true;
}
}
if (Addr.getOpcode() == ISD::OR &&
Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) {
Offset = Addr.getOperand(1).getOperand(0);
return true;
}
return false;
}

bool LanaiDAGToDAGISel::selectAddrRiSpls(SDValue Addr, SDValue &Base,
SDValue &Offset, SDValue &AluOp,
bool RiMode) {
SDLoc DL(Addr);

if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) {
if (RiMode) {
// Fits in 16-bit signed immediate.
if (isInt<16>(CN->getSExtValue())) {
int16_t Imm = CN->getSExtValue();
Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
return true;
}
// Allow SLS to match if the constant doesn't fit in 16 bits but can be
// represented as an SLS.
if (canBeRepresentedAsSls(*CN))
return false;
} else {
// Fits in 10-bit signed immediate.
if (isInt<10>(CN->getSExtValue())) {
int16_t Imm = CN->getSExtValue();
Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0));
Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0));
AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
return true;
}
}
}

// if Address is FI, get the TargetFrameIndex.
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Base = CurDAG->getTargetFrameIndex(
FIN->getIndex(),
getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
return true;
}

// Skip direct calls
if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
Addr.getOpcode() == ISD::TargetGlobalAddress))
return false;

// Address of the form imm + reg
ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode());
if (AluOperator == ISD::ADD) {
AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
// Addresses of the form FI+const
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
if ((RiMode && isInt<16>(CN->getSExtValue())) ||
(!RiMode && isInt<10>(CN->getSExtValue()))) {
// If the first operand is a FI, get the TargetFI Node
if (FrameIndexSDNode *FIN =
dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
Base = CurDAG->getTargetFrameIndex(
FIN->getIndex(),
getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
} else {
Base = Addr.getOperand(0);
}

Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i32);
return true;
}
}

// Let SLS match SMALL instead of RI.
if (AluOperator == ISD::OR && RiMode &&
Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
return false;

Base = Addr;
Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32);
return true;
}

bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr, SDValue &Base,
SDValue &Offset, SDValue &AluOp) {
return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RImode=*/true);
}

bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr, SDValue &Base,
SDValue &Offset, SDValue &AluOp) {
return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/false);
}

bool LanaiDAGToDAGISel::selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2,
SDValue &AluOp) {
// if Address is FI, get the TargetFrameIndex.
if (Addr.getOpcode() == ISD::FrameIndex)
return false;

// Skip direct calls
if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
Addr.getOpcode() == ISD::TargetGlobalAddress))
return false;

// Address of the form OP + OP
ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode());
LPAC::AluCode AluCode = LPAC::isdToLanaiAluCode(AluOperator);
if (AluCode != LPAC::UNKNOWN) {
// Skip addresses of the form FI OP const
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
if (isInt<16>(CN->getSExtValue()))
return false;

// Skip addresses with hi/lo operands
if (Addr.getOperand(0).getOpcode() == LanaiISD::HI ||
Addr.getOperand(0).getOpcode() == LanaiISD::LO ||
Addr.getOperand(0).getOpcode() == LanaiISD::SMALL ||
Addr.getOperand(1).getOpcode() == LanaiISD::HI ||
Addr.getOperand(1).getOpcode() == LanaiISD::LO ||
Addr.getOperand(1).getOpcode() == LanaiISD::SMALL)
return false;

// Addresses of the form register OP register
R1 = Addr.getOperand(0);
R2 = Addr.getOperand(1);
AluOp = CurDAG->getTargetConstant(AluCode, SDLoc(Addr), MVT::i32);
return true;
}

// Skip addresses with zero offset
return false;
}

bool LanaiDAGToDAGISel::SelectInlineAsmMemoryOperand(
const SDValue &Op, unsigned ConstraintCode, std::vector<SDValue> &OutOps) {
SDValue Op0, Op1, AluOp;
switch (ConstraintCode) {
default:
return true;
case InlineAsm::Constraint_m: // memory
if (!selectAddrRr(Op, Op0, Op1, AluOp) &&
!selectAddrRi(Op, Op0, Op1, AluOp))
return true;
break;
}

OutOps.push_back(Op0);
OutOps.push_back(Op1);
OutOps.push_back(AluOp);
return false;
}

// Select instructions not customized! Used for
// expanded, promoted and normal instructions
SDNode *LanaiDAGToDAGISel::Select(SDNode *Node) {
unsigned Opcode = Node->getOpcode();

// Dump information about the Node being selected
DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n");

// If we have a custom node, we already have selected!
if (Node->isMachineOpcode()) {
DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
return NULL;
}

// Instruction Selection not handled by the auto-generated
// tablegen selection should be handled here.
SDNode *ResNode = nullptr;
switch (Opcode) {
case ISD::FrameIndex:
ResNode = selectFrameIndex(Node);
break;
default:
break;
}

// Select the default instruction
if (ResNode == nullptr)
ResNode = SelectCode(Node);

DEBUG(errs() << "=> ");
if (ResNode == NULL || ResNode == Node)
DEBUG(Node->dump(CurDAG));
else
DEBUG(ResNode->dump(CurDAG));
DEBUG(errs() << "\n");
return ResNode;
}

SDNode *LanaiDAGToDAGISel::selectFrameIndex(SDNode *Node) {
SDLoc DL(Node);
SDValue Imm = CurDAG->getTargetConstant(0, DL, MVT::i32);
int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex();
EVT VT = Node->getValueType(0);
SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
unsigned Opc = Lanai::ADD_I_LO;
if (Node->hasOneUse())
return CurDAG->SelectNodeTo(Node, Opc, VT, TFI, Imm);
return CurDAG->getMachineNode(Opc, DL, VT, TFI, Imm);
}

// createLanaiISelDag - This pass converts a legalized DAG into a
// Lanai-specific DAG, ready for instruction scheduling.
FunctionPass *llvm::createLanaiISelDag(LanaiTargetMachine &TM) {
return new LanaiDAGToDAGISel(TM);
}
1,207 changes: 1,207 additions & 0 deletions llvm/lib/Target/Lanai/LanaiISelLowering.cpp

Large diffs are not rendered by default.

144 changes: 144 additions & 0 deletions llvm/lib/Target/Lanai/LanaiISelLowering.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
//===-- LanaiISelLowering.h - Lanai DAG Lowering Interface -....-*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interfaces that Lanai uses to lower LLVM code into a
// selection DAG.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_LANAI_LANAIISELLOWERING_H
#define LLVM_LIB_TARGET_LANAI_LANAIISELLOWERING_H

#include "Lanai.h"
#include "LanaiRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/Target/TargetLowering.h"

namespace llvm {
namespace LanaiISD {
enum {
FIRST_NUMBER = ISD::BUILTIN_OP_END,

ADJDYNALLOC,

// Return with a flag operand. Operand 0 is the chain operand.
RET_FLAG,

// CALL - These operations represent an abstract call instruction, which
// includes a bunch of information.
CALL,

// SELECT_CC - Operand 0 and operand 1 are selection variable, operand 3
// is condition code and operand 4 is flag operand.
SELECT_CC,

// SETCC - Store the conditional to a register
SETCC,

// SET_FLAG - Set flag compare
SET_FLAG,

// BR_CC - Used to glue together a conditional branch and comparison
BR_CC,

// Wrapper - A wrapper node for TargetConstantPool, TargetExternalSymbol,
// and TargetGlobalAddress.
Wrapper,

// Get the Higher/Lower 16 bits from a 32-bit immediate
HI,
LO,

// Small 21-bit immediate in global memory
SMALL
};
} // namespace LanaiISD

class LanaiSubtarget;

class LanaiTargetLowering : public TargetLowering {
public:
LanaiTargetLowering(const TargetMachine &TM, const LanaiSubtarget &STI);

// LowerOperation - Provide custom lowering hooks for some operations.
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;

// getTargetNodeName - This method returns the name of a target specific
// DAG node.
const char *getTargetNodeName(unsigned Opcode) const override;

SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCTTZ(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCTLZ(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCTTZ_ZERO_UNDEF(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;

unsigned getRegisterByName(const char *RegName, EVT VT,
SelectionDAG &DAG) const override;
std::pair<unsigned, const TargetRegisterClass *>
getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
StringRef Constraint, MVT VT) const override;
ConstraintWeight
getSingleConstraintMatchWeight(AsmOperandInfo &Info,
const char *Constraint) const override;
void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint,
std::vector<SDValue> &Ops,
SelectionDAG &DAG) const override;

private:
SDValue LowerCCCCallTo(SDValue Chain, SDValue Callee,
CallingConv::ID CallConv, bool IsVarArg,
bool IsTailCall,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl,
SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const;

SDValue LowerCCCArguments(SDValue Chain, CallingConv::ID CallConv,
bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL,
SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const;

SDValue LowerCallResult(SDValue Chain, SDValue InFlag,
CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL,
SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const;

SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const override;

SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv,
bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins,
SDLoc DL, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const override;

SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals, SDLoc DL,
SelectionDAG &DAG) const override;

const LanaiRegisterInfo *TRI;
};
} // namespace llvm

#endif // LLVM_LIB_TARGET_LANAI_LANAIISELLOWERING_H
561 changes: 561 additions & 0 deletions llvm/lib/Target/Lanai/LanaiInstrFormats.td

Large diffs are not rendered by default.

324 changes: 324 additions & 0 deletions llvm/lib/Target/Lanai/LanaiInstrInfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
//===-- LanaiInstrInfo.cpp - Lanai Instruction Information ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Lanai implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//

#include "Lanai.h"
#include "LanaiInstrInfo.h"
#include "LanaiMachineFunctionInfo.h"
#include "LanaiTargetMachine.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"

#define GET_INSTRINFO_CTOR_DTOR
#include "LanaiGenInstrInfo.inc"

namespace llvm {
LanaiInstrInfo::LanaiInstrInfo()
: LanaiGenInstrInfo(Lanai::ADJCALLSTACKDOWN, Lanai::ADJCALLSTACKUP),
RegisterInfo() {}

void LanaiInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator Position,
DebugLoc DL, unsigned DestinationRegister,
unsigned SourceRegister,
bool KillSource) const {
if (!Lanai::GPRRegClass.contains(DestinationRegister, SourceRegister)) {
llvm_unreachable("Impossible reg-to-reg copy");
}

BuildMI(MBB, Position, DL, get(Lanai::OR_I_LO), DestinationRegister)
.addReg(SourceRegister, getKillRegState(KillSource))
.addImm(0);
}

void LanaiInstrInfo::storeRegToStackSlot(
MachineBasicBlock &MBB, MachineBasicBlock::iterator Position,
unsigned SourceRegister, bool IsKill, int FrameIndex,
const TargetRegisterClass *RegisterClass,
const TargetRegisterInfo *RegisterInfo) const {
DebugLoc DL;
if (Position != MBB.end()) {
DL = Position->getDebugLoc();
}

if (!Lanai::GPRRegClass.hasSubClassEq(RegisterClass)) {
llvm_unreachable("Can't store this register to stack slot");
}
BuildMI(MBB, Position, DL, get(Lanai::SW_RI))
.addReg(SourceRegister, getKillRegState(IsKill))
.addFrameIndex(FrameIndex)
.addImm(0)
.addImm(LPAC::ADD);
}

void LanaiInstrInfo::loadRegFromStackSlot(
MachineBasicBlock &MBB, MachineBasicBlock::iterator Position,
unsigned DestinationRegister, int FrameIndex,
const TargetRegisterClass *RegisterClass,
const TargetRegisterInfo *RegisterInfo) const {
DebugLoc DL;
if (Position != MBB.end()) {
DL = Position->getDebugLoc();
}

if (!Lanai::GPRRegClass.hasSubClassEq(RegisterClass)) {
llvm_unreachable("Can't load this register from stack slot");
}
BuildMI(MBB, Position, DL, get(Lanai::LDW_RI), DestinationRegister)
.addFrameIndex(FrameIndex)
.addImm(0)
.addImm(LPAC::ADD);
}

bool LanaiInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const {
return false;
}

static LPCC::CondCode GetOppositeBranchCondition(LPCC::CondCode CC) {
switch (CC) {
case LPCC::ICC_T: // true
return LPCC::ICC_F;
case LPCC::ICC_F: // false
return LPCC::ICC_T;
case LPCC::ICC_HI: // high
return LPCC::ICC_LS;
case LPCC::ICC_LS: // low or same
return LPCC::ICC_HI;
case LPCC::ICC_CC: // carry cleared
return LPCC::ICC_CS;
case LPCC::ICC_CS: // carry set
return LPCC::ICC_CC;
case LPCC::ICC_NE: // not equal
return LPCC::ICC_EQ;
case LPCC::ICC_EQ: // equal
return LPCC::ICC_NE;
case LPCC::ICC_VC: // oVerflow cleared
return LPCC::ICC_VS;
case LPCC::ICC_VS: // oVerflow set
return LPCC::ICC_VC;
case LPCC::ICC_PL: // plus (note: 0 is "minus" too here)
return LPCC::ICC_MI;
case LPCC::ICC_MI: // minus
return LPCC::ICC_PL;
case LPCC::ICC_GE: // greater than or equal
return LPCC::ICC_LT;
case LPCC::ICC_LT: // less than
return LPCC::ICC_GE;
case LPCC::ICC_GT: // greater than
return LPCC::ICC_LE;
case LPCC::ICC_LE: // less than or equal
return LPCC::ICC_GT;
default:
llvm_unreachable("Invalid condtional code");
}
}

// The AnalyzeBranch function is used to examine conditional instructions and
// remove unnecessary instructions. This method is used by BranchFolder and
// IfConverter machine function passes to improve the CFG.
// - TrueBlock is set to the destination if condition evaluates true (it is the
// nullptr if the destination is the fall-through branch);
// - FalseBlock is set to the destination if condition evaluates to false (it
// is the nullptr if the branch is unconditional);
// - condition is populated with machine operands needed to generate the branch
// to insert in InsertBranch;
// Returns: false if branch could successfully be analyzed.
bool LanaiInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
MachineBasicBlock *&TrueBlock,
MachineBasicBlock *&FalseBlock,
SmallVectorImpl<MachineOperand> &Condition,
bool AllowModify) const {
// Iterator to current instruction being considered.
MachineBasicBlock::iterator Instruction = MBB.end();

// Start from the bottom of the block and work up, examining the
// terminator instructions.
while (Instruction != MBB.begin()) {
--Instruction;

// Skip over debug values.
if (Instruction->isDebugValue())
continue;

// Working from the bottom, when we see a non-terminator
// instruction, we're done.
if (!isUnpredicatedTerminator(*Instruction))
break;

// A terminator that isn't a branch can't easily be handled
// by this analysis.
if (!Instruction->isBranch())
return true;

// Handle unconditional branches.
if (Instruction->getOpcode() == Lanai::BT) {
if (!AllowModify) {
TrueBlock = Instruction->getOperand(0).getMBB();
continue;
}

// If the block has any instructions after a branch, delete them.
while (std::next(Instruction) != MBB.end()) {
std::next(Instruction)->eraseFromParent();
}

Condition.clear();
FalseBlock = nullptr;

// Delete the jump if it's equivalent to a fall-through.
if (MBB.isLayoutSuccessor(Instruction->getOperand(0).getMBB())) {
TrueBlock = nullptr;
Instruction->eraseFromParent();
Instruction = MBB.end();
continue;
}

// TrueBlock is used to indicate the unconditional destination.
TrueBlock = Instruction->getOperand(0).getMBB();
continue;
}

// Handle conditional branches
unsigned Opcode = Instruction->getOpcode();
if (Opcode != Lanai::BRCC)
return true; // Unknown opcode.

// Multiple conditional branches are not handled here so only proceed if
// there are no conditions enqueued.
if (Condition.empty()) {
LPCC::CondCode BranchCond =
static_cast<LPCC::CondCode>(Instruction->getOperand(1).getImm());

// TrueBlock is the target of the previously seen unconditional branch.
FalseBlock = TrueBlock;
TrueBlock = Instruction->getOperand(0).getMBB();
Condition.push_back(MachineOperand::CreateImm(BranchCond));
continue;
}

// Multiple conditional branches are not handled.
return true;
}

// Return false indicating branch successfully analyzed.
return false;
}

// ReverseBranchCondition - Reverses the branch condition of the specified
// condition list, returning false on success and true if it cannot be
// reversed.
bool LanaiInstrInfo::ReverseBranchCondition(
SmallVectorImpl<llvm::MachineOperand> &Condition) const {
assert((Condition.size() == 1) &&
"Lanai branch conditions should have one component.");

LPCC::CondCode BranchCond =
static_cast<LPCC::CondCode>(Condition[0].getImm());
Condition[0].setImm(GetOppositeBranchCondition(BranchCond));
return false;
}

// Insert the branch with condition specified in condition and given targets
// (TrueBlock and FalseBlock). This function returns the number of machine
// instructions inserted.
unsigned LanaiInstrInfo::InsertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TrueBlock,
MachineBasicBlock *FalseBlock,
ArrayRef<MachineOperand> Condition,
DebugLoc DL) const {
// Shouldn't be a fall through.
assert(TrueBlock && "InsertBranch must not be told to insert a fallthrough");

// If condition is empty then an unconditional branch is being inserted.
if (Condition.empty()) {
assert(!FalseBlock && "Unconditional branch with multiple successors!");
BuildMI(&MBB, DL, get(Lanai::BT)).addMBB(TrueBlock);
return 1;
}

// Else a conditional branch is inserted.
assert((Condition.size() == 1) &&
"Lanai branch conditions should have one component.");
unsigned ConditionalCode = Condition[0].getImm();
BuildMI(&MBB, DL, get(Lanai::BRCC)).addMBB(TrueBlock).addImm(ConditionalCode);

// If no false block, then false behavior is fall through and no branch needs
// to be inserted.
if (!FalseBlock)
return 1;

BuildMI(&MBB, DL, get(Lanai::BT)).addMBB(FalseBlock);
return 2;
}

unsigned LanaiInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator Instruction = MBB.end();
unsigned Count = 0;

while (Instruction != MBB.begin()) {
--Instruction;
if (Instruction->isDebugValue())
continue;
if (Instruction->getOpcode() != Lanai::BT &&
Instruction->getOpcode() != Lanai::BRCC) {
break;
}

// Remove the branch.
Instruction->eraseFromParent();
Instruction = MBB.end();
++Count;
}

return Count;
}

unsigned LanaiInstrInfo::isLoadFromStackSlot(const MachineInstr *MI,
int &FrameIndex) const {
if (MI->getOpcode() == Lanai::LDW_RI)
if (MI->getOperand(1).isFI() && MI->getOperand(2).isImm() &&
MI->getOperand(2).getImm() == 0) {
FrameIndex = MI->getOperand(1).getIndex();
return MI->getOperand(0).getReg();
}
return 0;
}

unsigned LanaiInstrInfo::isLoadFromStackSlotPostFE(const MachineInstr *MI,
int &FrameIndex) const {
if (MI->getOpcode() == Lanai::LDW_RI) {
unsigned Reg;
if ((Reg = isLoadFromStackSlot(MI, FrameIndex)))
return Reg;
// Check for post-frame index elimination operations
const MachineMemOperand *Dummy;
return hasLoadFromStackSlot(MI, Dummy, FrameIndex);
}
return 0;
}

unsigned LanaiInstrInfo::isStoreToStackSlot(const MachineInstr *MI,
int &FrameIndex) const {
if (MI->getOpcode() == Lanai::SW_RI)
if (MI->getOperand(0).isFI() && MI->getOperand(1).isImm() &&
MI->getOperand(1).getImm() == 0) {
FrameIndex = MI->getOperand(0).getIndex();
return MI->getOperand(2).getReg();
}
return 0;
}
} // namespace llvm
126 changes: 126 additions & 0 deletions llvm/lib/Target/Lanai/LanaiInstrInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//===- LanaiInstrInfo.h - Lanai Instruction Information ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Lanai implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_LANAI_LANAIINSTRINFO_H
#define LLVM_LIB_TARGET_LANAI_LANAIINSTRINFO_H

#include "LanaiRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"

#define GET_INSTRINFO_HEADER
#include "LanaiGenInstrInfo.inc"

namespace llvm {

class LanaiInstrInfo : public LanaiGenInstrInfo {
const LanaiRegisterInfo RegisterInfo;

public:
LanaiInstrInfo();

// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
// such, whenever a client has an instance of instruction info, it should
// always be able to get register info as well (through this method).
virtual const LanaiRegisterInfo &getRegisterInfo() const {
return RegisterInfo;
}

unsigned isLoadFromStackSlot(const MachineInstr *MI,
int &FrameIndex) const override;

unsigned isLoadFromStackSlotPostFE(const MachineInstr *MI,
int &FrameIndex) const override;

unsigned isStoreToStackSlot(const MachineInstr *MI,
int &FrameIndex) const override;

void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator Position,
DebugLoc DL, unsigned DestinationRegister,
unsigned SourceRegister, bool KillSource) const override;

void
storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator Position,
unsigned SourceRegister, bool IsKill, int FrameIndex,
const TargetRegisterClass *RegisterClass,
const TargetRegisterInfo *RegisterInfo) const override;

void
loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator Position,
unsigned DestinationRegister, int FrameIndex,
const TargetRegisterClass *RegisterClass,
const TargetRegisterInfo *RegisterInfo) const override;

bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const override;

bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TrueBlock,
MachineBasicBlock *&FalseBlock,
SmallVectorImpl<MachineOperand> &Condition,
bool AllowModify) const override;

unsigned RemoveBranch(MachineBasicBlock &MBB) const override;

bool ReverseBranchCondition(
SmallVectorImpl<MachineOperand> &Condition) const override;

unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TrueBlock,
MachineBasicBlock *FalseBlock,
ArrayRef<MachineOperand> Condition,
DebugLoc DL) const override;
};

static inline bool isSPLSOpcode(unsigned Opcode) {
switch (Opcode) {
case Lanai::LDBs_RI:
case Lanai::LDBz_RI:
case Lanai::LDHs_RI:
case Lanai::LDHz_RI:
case Lanai::STB_RI:
case Lanai::STH_RI:
return true;
default:
return false;
}
}

static inline bool isRMOpcode(unsigned Opcode) {
switch (Opcode) {
case Lanai::LDW_RI:
case Lanai::SW_RI:
return true;
default:
return false;
}
}

static inline bool isRRMOpcode(unsigned Opcode) {
switch (Opcode) {
case Lanai::LDBs_RR:
case Lanai::LDBz_RR:
case Lanai::LDHs_RR:
case Lanai::LDHz_RR:
case Lanai::LDWz_RR:
case Lanai::LDW_RR:
case Lanai::STB_RR:
case Lanai::STH_RR:
case Lanai::SW_RR:
return true;
default:
return false;
}
}

} // namespace llvm

#endif // LLVM_LIB_TARGET_LANAI_LANAIINSTRINFO_H
Loading