183 changes: 183 additions & 0 deletions llvm/lib/Target/ARC/ARCBranchFinalize.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
//===- ARCBranchFinalize.cpp - ARC conditional branches ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass takes existing conditional branches and expands them into longer
// range conditional branches.
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "arc-branch-finalize"

#include "ARCInstrInfo.h"
#include "ARCTargetMachine.h"
#include "MCTargetDesc/ARCInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetInstrInfo.h"
#include <vector>

using namespace llvm;

namespace llvm {

void initializeARCBranchFinalizePass(PassRegistry &Registry);
FunctionPass *createARCBranchFinalizePass();

} // end namespace llvm

namespace {

class ARCBranchFinalize : public MachineFunctionPass {
public:
static char ID;

ARCBranchFinalize() : MachineFunctionPass(ID) {
initializeARCBranchFinalizePass(*PassRegistry::getPassRegistry());
}

StringRef getPassName() const override {
return "ARC Branch Finalization Pass";
}

bool runOnMachineFunction(MachineFunction &MF) override;
void replaceWithBRcc(MachineInstr *MI) const;
void replaceWithCmpBcc(MachineInstr *MI) const;

private:
const ARCInstrInfo *TII{nullptr};
};

char ARCBranchFinalize::ID = 0;

} // end anonymous namespace

INITIALIZE_PASS_BEGIN(ARCBranchFinalize, "arc-branch-finalize",
"ARC finalize branches", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_END(ARCBranchFinalize, "arc-branch-finalize",
"ARC finalize branches", false, false)

// BRcc has 6 supported condition codes, which differ from the 16
// condition codes supported in the predicated instructions:
// EQ -- 000
// NE -- 001
// LT -- 010
// GE -- 011
// LO -- 100
// HS -- 101
static unsigned getCCForBRcc(unsigned CC) {
switch (CC) {
case ARCCC::EQ:
return 0;
case ARCCC::NE:
return 1;
case ARCCC::LT:
return 2;
case ARCCC::GE:
return 3;
case ARCCC::LO:
return 4;
case ARCCC::HS:
return 5;
default:
return -1U;
}
}

static bool isBRccPseudo(MachineInstr *MI) {
return !(MI->getOpcode() != ARC::BRcc_rr_p &&
MI->getOpcode() != ARC::BRcc_ru6_p);
}

static unsigned getBRccForPseudo(MachineInstr *MI) {
assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction.");
if (MI->getOpcode() == ARC::BRcc_rr_p)
return ARC::BRcc_rr;
return ARC::BRcc_ru6;
}

static unsigned getCmpForPseudo(MachineInstr *MI) {
assert(isBRccPseudo(MI) && "Can't get BRcc for wrong instruction.");
if (MI->getOpcode() == ARC::BRcc_rr_p)
return ARC::CMP_rr;
return ARC::CMP_ru6;
}

void ARCBranchFinalize::replaceWithBRcc(MachineInstr *MI) const {
DEBUG(dbgs() << "Replacing pseudo branch with BRcc\n");
unsigned CC = getCCForBRcc(MI->getOperand(3).getImm());
if (CC != -1U) {
BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
TII->get(getBRccForPseudo(MI)))
.addMBB(MI->getOperand(0).getMBB())
.addReg(MI->getOperand(1).getReg())
.add(MI->getOperand(2))
.addImm(getCCForBRcc(MI->getOperand(3).getImm()));
MI->eraseFromParent();
} else {
replaceWithCmpBcc(MI);
}
}

void ARCBranchFinalize::replaceWithCmpBcc(MachineInstr *MI) const {
DEBUG(dbgs() << "Branch: " << *MI << "\n");
DEBUG(dbgs() << "Replacing pseudo branch with Cmp + Bcc\n");
BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
TII->get(getCmpForPseudo(MI)))
.addReg(MI->getOperand(1).getReg())
.add(MI->getOperand(2));
BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(ARC::Bcc))
.addMBB(MI->getOperand(0).getMBB())
.addImm(MI->getOperand(3).getImm());
MI->eraseFromParent();
}

bool ARCBranchFinalize::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "Running ARC Branch Finalize on "
<< MF.getFunction()->getName() << "\n");
std::vector<MachineInstr *> Branches;
bool Changed = false;
unsigned MaxSize = 0;
TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
std::map<MachineBasicBlock *, unsigned> BlockToPCMap;
std::vector<std::pair<MachineInstr *, unsigned>> BranchToPCList;
unsigned PC = 0;

for (auto &MBB : MF) {
BlockToPCMap.insert(std::make_pair(&MBB, PC));
for (auto &MI : MBB) {
unsigned Size = TII->getInstSizeInBytes(MI);
if (Size > 8 || Size == 0) {
DEBUG(dbgs() << "Unknown (or size 0) size for: " << MI << "\n");
} else {
MaxSize += Size;
}
if (MI.isBranch()) {
Branches.push_back(&MI);
BranchToPCList.emplace_back(&MI, PC);
}
PC += Size;
}
}
for (auto P : BranchToPCList) {
if (isBRccPseudo(P.first))
isInt<9>(MaxSize) ? replaceWithBRcc(P.first) : replaceWithCmpBcc(P.first);
}

DEBUG(dbgs() << "Estimated function size for " << MF.getFunction()->getName()
<< ": " << MaxSize << "\n");

return Changed;
}

FunctionPass *llvm::createARCBranchFinalizePass() {
return new ARCBranchFinalize();
}
41 changes: 41 additions & 0 deletions llvm/lib/Target/ARC/ARCCallingConv.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===- ARCCallingConv.td - Calling Conventions for ARC -----*- 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 ARC architecture.
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// ARC Return Value Calling Convention
//===----------------------------------------------------------------------===//
def RetCC_ARC : CallingConv<[
// i32 are returned in registers R0, R1, R2, R3
CCIfType<[i32, i64], CCAssignToReg<[R0, R1, R2, R3]>>,

// Integer values get stored in stack slots that are 4 bytes in
// size and 4-byte aligned.
CCIfType<[i64], CCAssignToStack<8, 4>>,
CCIfType<[i32], CCAssignToStack<4, 4>>
]>;

//===----------------------------------------------------------------------===//
// ARC Argument Calling Conventions
//===----------------------------------------------------------------------===//
def CC_ARC : CallingConv<[
// Promote i8/i16 arguments to i32.
CCIfType<[i8, i16], CCPromoteToType<i32>>,

// The first 8 integer arguments are passed in integer registers.
CCIfType<[i32, i64], CCAssignToReg<[R0, R1, R2, R3, R4, R5, R6, R7]>>,

// Integer values get stored in stack slots that are 4 bytes in
// size and 4-byte aligned.
CCIfType<[i64], CCAssignToStack<8, 4>>,
CCIfType<[i32], CCAssignToStack<4, 4>>
]>;

def CSR_ARC : CalleeSavedRegs<(add (sequence "R%u", 13, 25), GP, FP)>;
103 changes: 103 additions & 0 deletions llvm/lib/Target/ARC/ARCExpandPseudos.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//===- ARCExpandPseudosPass - ARC expand pseudo loads -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass expands stores with large offsets into an appropriate sequence.
//===----------------------------------------------------------------------===//

#include "ARC.h"
#include "ARCInstrInfo.h"
#include "ARCRegisterInfo.h"
#include "ARCSubtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"

using namespace llvm;

#define DEBUG_TYPE "arc-expand-pseudos"

namespace {

class ARCExpandPseudos : public MachineFunctionPass {
public:
static char ID;
ARCExpandPseudos() : MachineFunctionPass(ID) {}

bool runOnMachineFunction(MachineFunction &Fn) override;

StringRef getPassName() const override { return "ARC Expand Pseudos"; }

private:
void ExpandStore(MachineFunction &, MachineBasicBlock::iterator);

const ARCInstrInfo *TII;
};

char ARCExpandPseudos::ID = 0;

} // end anonymous namespace

static unsigned getMappedOp(unsigned PseudoOp) {
switch (PseudoOp) {
case ARC::ST_FAR:
return ARC::ST_rs9;
case ARC::STH_FAR:
return ARC::STH_rs9;
case ARC::STB_FAR:
return ARC::STB_rs9;
default:
llvm_unreachable("Unhandled pseudo op.");
}
}

void ARCExpandPseudos::ExpandStore(MachineFunction &MF,
MachineBasicBlock::iterator SII) {
MachineInstr &SI = *SII;
unsigned AddrReg = MF.getRegInfo().createVirtualRegister(&ARC::GPR32RegClass);
unsigned AddOpc =
isUInt<6>(SI.getOperand(2).getImm()) ? ARC::ADD_rru6 : ARC::ADD_rrlimm;
BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(AddOpc), AddrReg)
.addReg(SI.getOperand(1).getReg())
.addImm(SI.getOperand(2).getImm());
BuildMI(*SI.getParent(), SI, SI.getDebugLoc(),
TII->get(getMappedOp(SI.getOpcode())))
.addReg(SI.getOperand(0).getReg())
.addReg(AddrReg)
.addImm(0);
SI.eraseFromParent();
}

bool ARCExpandPseudos::runOnMachineFunction(MachineFunction &MF) {
const ARCSubtarget *STI = &MF.getSubtarget<ARCSubtarget>();
TII = STI->getInstrInfo();
bool ExpandedStore = false;
for (auto &MBB : MF) {
MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
while (MBBI != E) {
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
switch (MBBI->getOpcode()) {
case ARC::ST_FAR:
case ARC::STH_FAR:
case ARC::STB_FAR:
ExpandStore(MF, MBBI);
ExpandedStore = true;
break;
default:
break;
}
MBBI = NMBBI;
}
}
return ExpandedStore;
}

FunctionPass *llvm::createARCExpandPseudosPass() {
return new ARCExpandPseudos();
}
472 changes: 472 additions & 0 deletions llvm/lib/Target/ARC/ARCFrameLowering.cpp

Large diffs are not rendered by default.

78 changes: 78 additions & 0 deletions llvm/lib/Target/ARC/ARCFrameLowering.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//===- ARCFrameLowering.h - Define frame lowering for ARC -------*- 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 the ARC specific frame lowering.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_ARC_ARCFRAMELOWERING_H
#define LLVM_LIB_TARGET_ARC_ARCFRAMELOWERING_H

#include "ARC.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetFrameLowering.h"

namespace llvm {

class MachineFunction;
class ARCSubtarget;
class ARCInstrInfo;

class ARCFrameLowering : public TargetFrameLowering {
public:
ARCFrameLowering(const ARCSubtarget &st)
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 4, 0), ST(st) {
}

/// Insert Prologue into the function.
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;

/// Insert Epilogue into the function.
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;

/// Add explicit callee save registers.
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
RegScavenger *RS) const override;

bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const override;

bool
restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const override;

void processFunctionBeforeFrameFinalized(MachineFunction &MF,
RegScavenger *RS) const override;

bool hasFP(const MachineFunction &MF) const override;

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

bool assignCalleeSavedSpillSlots(
llvm::MachineFunction &, const llvm::TargetRegisterInfo *,
std::vector<llvm::CalleeSavedInfo> &) const override;

private:
void adjustStackToMatchRecords(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
bool allocate) const;

const ARCSubtarget &ST;
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_ARCFRAMELOWERING_H
182 changes: 182 additions & 0 deletions llvm/lib/Target/ARC/ARCISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
//===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- 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 an instruction selector for the ARC target.
//
//===----------------------------------------------------------------------===//

#include "ARC.h"
#include "ARCTargetMachine.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetLowering.h"

using namespace llvm;

/// ARCDAGToDAGISel - ARC specific code to select ARC machine
/// instructions for SelectionDAG operations.
namespace {

class ARCDAGToDAGISel : public SelectionDAGISel {
public:
ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOpt::Level OptLevel)
: SelectionDAGISel(TM, OptLevel) {}

void Select(SDNode *N) override;

// Complex Pattern Selectors.
bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset);
bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset);
bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset);
bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset);
bool SelectCMOVPred(SDValue N, SDValue &Pred, SDValue &Reg) {
const ConstantSDNode *CN = cast<ConstantSDNode>(N);
Pred = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), MVT::i32);
Reg = CurDAG->getRegister(ARC::STATUS32, MVT::i32);
return true;
}

StringRef getPassName() const override {
return "ARC DAG->DAG Pattern Instruction Selection";
}

// Include the pieces autogenerated from the target description.
#include "ARCGenDAGISel.inc"
};

} // end anonymous namespace

/// This pass converts a legalized DAG into a ARC-specific DAG, ready for
/// instruction scheduling.
FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM,
CodeGenOpt::Level OptLevel) {
return new ARCDAGToDAGISel(TM, OptLevel);
}

bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base,
SDValue &Offset) {
if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
Base = Addr.getOperand(0);
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
return true;
}
return false;
}

bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base,
SDValue &Offset) {
if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
return false;
}

if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB &&
!CurDAG->isBaseWithConstantOffset(Addr)) {
if (Addr.getOpcode() == ISD::FrameIndex) {
// Match frame index.
int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
Base = CurDAG->getTargetFrameIndex(
FI, TLI->getPointerTy(CurDAG->getDataLayout()));
} else {
Base = Addr;
}
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
return true;
}

if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
int32_t RHSC = RHS->getSExtValue();
if (Addr.getOpcode() == ISD::SUB)
RHSC = -RHSC;

// Do we need more than 9 bits to encode?
if (!isInt<9>(RHSC))
return false;
Base = Addr.getOperand(0);
if (Base.getOpcode() == ISD::FrameIndex) {
int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Base = CurDAG->getTargetFrameIndex(
FI, TLI->getPointerTy(CurDAG->getDataLayout()));
}
Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
return true;
}
Base = Addr;
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
return true;
}

bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base,
SDValue &Offset) {
if (SelectAddrModeS9(Addr, Base, Offset))
return false;
if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
return false;
}
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
int32_t RHSC = RHS->getSExtValue();
if (Addr.getOpcode() == ISD::SUB)
RHSC = -RHSC;
Base = Addr.getOperand(0);
Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
return true;
}
return false;
}

// Is this a legal frame index addressing expression.
bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base,
SDValue &Offset) {
FrameIndexSDNode *FIN = nullptr;
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
return true;
}
if (Addr.getOpcode() == ISD::ADD) {
ConstantSDNode *CN = nullptr;
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) &&
(CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
(CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
// Constant positive word offset from frame index
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
Offset =
CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32);
return true;
}
}
return false;
}

void ARCDAGToDAGISel::Select(SDNode *N) {
switch (N->getOpcode()) {
case ISD::Constant: {
uint64_t CVal = cast<ConstantSDNode>(N)->getZExtValue();
ReplaceNode(N, CurDAG->getMachineNode(
isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm,
SDLoc(N), MVT::i32,
CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32)));
return;
}
}
SelectCode(N);
}
767 changes: 767 additions & 0 deletions llvm/lib/Target/ARC/ARCISelLowering.cpp

Large diffs are not rendered by default.

121 changes: 121 additions & 0 deletions llvm/lib/Target/ARC/ARCISelLowering.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//===- ARCISelLowering.h - ARC 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 ARC uses to lower LLVM code into a
// selection DAG.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_ARC_ARCISELLOWERING_H
#define LLVM_LIB_TARGET_ARC_ARCISELLOWERING_H

#include "ARC.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/Target/TargetLowering.h"

namespace llvm {

// Forward delcarations
class ARCSubtarget;
class ARCTargetMachine;

namespace ARCISD {

enum NodeType : unsigned {
// Start the numbering where the builtin ops and target ops leave off.
FIRST_NUMBER = ISD::BUILTIN_OP_END,

// Branch and link (call)
BL,

// Jump and link (indirect call)
JL,

// CMP
CMP,

// CMOV
CMOV,

// BRcc
BRcc,

// Global Address Wrapper
GAWRAPPER,

// return, (j_s [blink])
RET
};

} // end namespace ARCISD

//===--------------------------------------------------------------------===//
// TargetLowering Implementation
//===--------------------------------------------------------------------===//
class ARCTargetLowering : public TargetLowering {
public:
explicit ARCTargetLowering(const TargetMachine &TM,
const ARCSubtarget &Subtarget);

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

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

/// Return true if the addressing mode represented by AM is legal for this
/// target, for a load/store of the specified type.
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty,
unsigned AS,
Instruction *I = nullptr) const override;

private:
const TargetMachine &TM;
const ARCSubtarget &Subtarget;

// Lower Operand helpers
SDValue LowerCallArguments(SDValue Chain, CallingConv::ID CallConv,
bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins,
SDLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const;
// Lower Operand specifics
SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSIGN_EXTEND_INREG(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override;

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

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

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

bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF,
bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &ArgsFlags,
LLVMContext &Context) const override;

bool mayBeEmittedAsTailCall(const CallInst *CI) const override;
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_ARCISELLOWERING_H
508 changes: 508 additions & 0 deletions llvm/lib/Target/ARC/ARCInstrFormats.td

Large diffs are not rendered by default.

394 changes: 394 additions & 0 deletions llvm/lib/Target/ARC/ARCInstrInfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,394 @@
//===- ARCInstrInfo.cpp - ARC 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 ARC implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//

#include "ARCInstrInfo.h"
#include "ARC.h"
#include "ARCMachineFunctionInfo.h"
#include "ARCSubtarget.h"
#include "MCTargetDesc/ARCInfo.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/TargetRegistry.h"

using namespace llvm;

#define GET_INSTRINFO_CTOR_DTOR
#include "ARCGenInstrInfo.inc"

#define DEBUG_TYPE "arc-inst-info"
// Pin the vtable to this file.
void ARCInstrInfo::anchor() {}

ARCInstrInfo::ARCInstrInfo()
: ARCGenInstrInfo(ARC::ADJCALLSTACKDOWN, ARC::ADJCALLSTACKUP), RI() {}

static bool isZeroImm(const MachineOperand &Op) {
return Op.isImm() && Op.getImm() == 0;
}

static bool isLoad(int Opcode) {
return Opcode == ARC::LD_rs9 || Opcode == ARC::LDH_rs9 ||
Opcode == ARC::LDB_rs9;
}

static bool isStore(int Opcode) {
return Opcode == ARC::ST_rs9 || Opcode == ARC::STH_rs9 ||
Opcode == ARC::STB_rs9;
}

/// If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
unsigned ARCInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
int &FrameIndex) const {
int Opcode = MI.getOpcode();
if (isLoad(Opcode)) {
if ((MI.getOperand(1).isFI()) && // is a stack slot
(MI.getOperand(2).isImm()) && // the imm is zero
(isZeroImm(MI.getOperand(2)))) {
FrameIndex = MI.getOperand(1).getIndex();
return MI.getOperand(0).getReg();
}
}
return 0;
}

/// If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
unsigned ARCInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
int &FrameIndex) const {
int Opcode = MI.getOpcode();
if (isStore(Opcode)) {
if ((MI.getOperand(1).isFI()) && // is a stack slot
(MI.getOperand(2).isImm()) && // the imm is zero
(isZeroImm(MI.getOperand(2)))) {
FrameIndex = MI.getOperand(1).getIndex();
return MI.getOperand(0).getReg();
}
}
return 0;
}

/// Return the inverse of passed condition, i.e. turning COND_E to COND_NE.
static ARCCC::CondCode GetOppositeBranchCondition(ARCCC::CondCode CC) {
switch (CC) {
default:
llvm_unreachable("Illegal condition code!");
case ARCCC::EQ:
return ARCCC::NE;
case ARCCC::NE:
return ARCCC::EQ;
case ARCCC::LO:
return ARCCC::HS;
case ARCCC::HS:
return ARCCC::LO;
case ARCCC::GT:
return ARCCC::LE;
case ARCCC::GE:
return ARCCC::LT;
case ARCCC::LT:
return ARCCC::GE;
case ARCCC::LE:
return ARCCC::GT;
case ARCCC::HI:
return ARCCC::LS;
case ARCCC::LS:
return ARCCC::HI;
case ARCCC::NZ:
return ARCCC::Z;
case ARCCC::Z:
return ARCCC::NZ;
}
}

static bool isUncondBranchOpcode(int Opc) { return Opc == ARC::BR; }

static bool isCondBranchOpcode(int Opc) {
return Opc == ARC::BRcc_rr_p || Opc == ARC::BRcc_ru6_p;
}

static bool isJumpOpcode(int Opc) { return Opc == ARC::J; }

/// Analyze the branching code at the end of MBB, returning
/// true if it cannot be understood (e.g. it's a switch dispatch or isn't
/// implemented for a target). Upon success, this returns false and returns
/// with the following information in various cases:
///
/// 1. If this block ends with no branches (it just falls through to its succ)
/// just return false, leaving TBB/FBB null.
/// 2. If this block ends with only an unconditional branch, it sets TBB to be
/// the destination block.
/// 3. If this block ends with a conditional branch and it falls through to a
/// successor block, it sets TBB to be the branch destination block and a
/// list of operands that evaluate the condition. These operands can be
/// passed to other TargetInstrInfo methods to create new branches.
/// 4. If this block ends with a conditional branch followed by an
/// unconditional branch, it returns the 'true' destination in TBB, the
/// 'false' destination in FBB, and a list of operands that evaluate the
/// condition. These operands can be passed to other TargetInstrInfo
/// methods to create new branches.
///
/// Note that RemoveBranch and InsertBranch must be implemented to support
/// cases where this method returns success.
///
/// If AllowModify is true, then this routine is allowed to modify the basic
/// block (e.g. delete instructions after the unconditional branch).

bool ARCInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const {
TBB = FBB = nullptr;
MachineBasicBlock::iterator I = MBB.end();
if (I == MBB.begin())
return false;
--I;

while (isPredicated(*I) || I->isTerminator() || I->isDebugValue()) {
// Flag to be raised on unanalyzeable instructions. This is useful in cases
// where we want to clean up on the end of the basic block before we bail
// out.
bool CantAnalyze = false;

// Skip over DEBUG values and predicated nonterminators.
while (I->isDebugValue() || !I->isTerminator()) {
if (I == MBB.begin())
return false;
--I;
}

if (isJumpOpcode(I->getOpcode())) {
// Indirect branches and jump tables can't be analyzed, but we still want
// to clean up any instructions at the tail of the basic block.
CantAnalyze = true;
} else if (isUncondBranchOpcode(I->getOpcode())) {
TBB = I->getOperand(0).getMBB();
} else if (isCondBranchOpcode(I->getOpcode())) {
// Bail out if we encounter multiple conditional branches.
if (!Cond.empty())
return true;

assert(!FBB && "FBB should have been null.");
FBB = TBB;
TBB = I->getOperand(0).getMBB();
Cond.push_back(I->getOperand(1));
Cond.push_back(I->getOperand(2));
Cond.push_back(I->getOperand(3));
} else if (I->isReturn()) {
// Returns can't be analyzed, but we should run cleanup.
CantAnalyze = !isPredicated(*I);
} else {
// We encountered other unrecognized terminator. Bail out immediately.
return true;
}

// Cleanup code - to be run for unpredicated unconditional branches and
// returns.
if (!isPredicated(*I) && (isUncondBranchOpcode(I->getOpcode()) ||
isJumpOpcode(I->getOpcode()) || I->isReturn())) {
// Forget any previous condition branch information - it no longer
// applies.
Cond.clear();
FBB = nullptr;

// If we can modify the function, delete everything below this
// unconditional branch.
if (AllowModify) {
MachineBasicBlock::iterator DI = std::next(I);
while (DI != MBB.end()) {
MachineInstr &InstToDelete = *DI;
++DI;
InstToDelete.eraseFromParent();
}
}
}

if (CantAnalyze)
return true;

if (I == MBB.begin())
return false;

--I;
}

// We made it past the terminators without bailing out - we must have
// analyzed this branch successfully.
return false;
}

unsigned ARCInstrInfo::removeBranch(MachineBasicBlock &MBB,
int *BytesRemoved) const {
assert(!BytesRemoved && "Code size not handled");
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
if (I == MBB.end())
return 0;

if (!isUncondBranchOpcode(I->getOpcode()) &&
!isCondBranchOpcode(I->getOpcode()))
return 0;

// Remove the branch.
I->eraseFromParent();

I = MBB.end();

if (I == MBB.begin())
return 1;
--I;
if (!isCondBranchOpcode(I->getOpcode()))
return 1;

// Remove the branch.
I->eraseFromParent();
return 2;
}

void ARCInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
const DebugLoc &dl, unsigned DestReg,
unsigned SrcReg, bool KillSrc) const {
assert(ARC::GPR32RegClass.contains(SrcReg) &&
"Only GPR32 src copy supported.");
assert(ARC::GPR32RegClass.contains(DestReg) &&
"Only GPR32 dest copy supported.");
BuildMI(MBB, I, dl, get(ARC::MOV_rr), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
}

void ARCInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned SrcReg, bool isKill,
int FrameIndex,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
DebugLoc dl = MBB.findDebugLoc(I);
MachineFunction &MF = *MBB.getParent();
MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Align = MFI.getObjectAlignment(FrameIndex);

MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FrameIndex),
MachineMemOperand::MOStore, MFI.getObjectSize(FrameIndex), Align);

assert(MMO && "Couldn't get MachineMemOperand for store to stack.");
assert(TRI->getSpillSize(*RC) == 4 &&
"Only support 4-byte stores to stack now.");
assert(ARC::GPR32RegClass.hasSubClassEq(RC) &&
"Only support GPR32 stores to stack now.");
DEBUG(dbgs() << "Created store reg=" << PrintReg(SrcReg, TRI)
<< " to FrameIndex=" << FrameIndex << "\n");
BuildMI(MBB, I, dl, get(ARC::ST_rs9))
.addReg(SrcReg, getKillRegState(isKill))
.addFrameIndex(FrameIndex)
.addImm(0)
.addMemOperand(MMO);
}

void ARCInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned DestReg, int FrameIndex,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
DebugLoc dl = MBB.findDebugLoc(I);
MachineFunction &MF = *MBB.getParent();
MachineFrameInfo &MFI = MF.getFrameInfo();
unsigned Align = MFI.getObjectAlignment(FrameIndex);
MachineMemOperand *MMO = MF.getMachineMemOperand(
MachinePointerInfo::getFixedStack(MF, FrameIndex),
MachineMemOperand::MOLoad, MFI.getObjectSize(FrameIndex), Align);

assert(MMO && "Couldn't get MachineMemOperand for store to stack.");
assert(TRI->getSpillSize(*RC) == 4 &&
"Only support 4-byte loads from stack now.");
assert(ARC::GPR32RegClass.hasSubClassEq(RC) &&
"Only support GPR32 stores to stack now.");
DEBUG(dbgs() << "Created load reg=" << PrintReg(DestReg, TRI)
<< " from FrameIndex=" << FrameIndex << "\n");
BuildMI(MBB, I, dl, get(ARC::LD_rs9))
.addReg(DestReg, RegState::Define)
.addFrameIndex(FrameIndex)
.addImm(0)
.addMemOperand(MMO);
}

/// Return the inverse opcode of the specified Branch instruction.
bool ARCInstrInfo::reverseBranchCondition(
SmallVectorImpl<MachineOperand> &Cond) const {
assert((Cond.size() == 3) && "Invalid ARC branch condition!");
Cond[2].setImm(GetOppositeBranchCondition((ARCCC::CondCode)Cond[2].getImm()));
return false;
}

MachineBasicBlock::iterator
ARCInstrInfo::loadImmediate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI, unsigned Reg,
uint64_t Value) const {
DebugLoc dl = MBB.findDebugLoc(MI);
if (isInt<12>(Value)) {
return BuildMI(MBB, MI, dl, get(ARC::MOV_rs12), Reg)
.addImm(Value)
.getInstr();
}
llvm_unreachable("Need Arc long immediate instructions.");
}

unsigned ARCInstrInfo::insertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
const DebugLoc &dl, int *BytesAdded) const {
assert(!BytesAdded && "Code size not handled.");

// Shouldn't be a fall through.
assert(TBB && "InsertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 3 || Cond.size() == 0) &&
"ARC branch conditions have two components!");

if (Cond.empty()) {
BuildMI(&MBB, dl, get(ARC::BR)).addMBB(TBB);
return 1;
}
int BccOpc = Cond[1].isImm() ? ARC::BRcc_ru6_p : ARC::BRcc_rr_p;
MachineInstrBuilder MIB = BuildMI(&MBB, dl, get(BccOpc));
MIB.addMBB(TBB);
for (unsigned i = 0; i < 3; i++) {
MIB.add(Cond[i]);
}

// One-way conditional branch.
if (!FBB) {
return 1;
}

// Two-way conditional branch.
BuildMI(&MBB, dl, get(ARC::BR)).addMBB(FBB);
return 2;
}

unsigned ARCInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
if (MI.getOpcode() == TargetOpcode::INLINEASM) {
const MachineFunction *MF = MI.getParent()->getParent();
const char *AsmStr = MI.getOperand(0).getSymbolName();
return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo());
}
return MI.getDesc().getSize();
}
94 changes: 94 additions & 0 deletions llvm/lib/Target/ARC/ARCInstrInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//===- ARCInstrInfo.h - ARC 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 ARC implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_ARC_ARCINSTRINFO_H
#define LLVM_LIB_TARGET_ARC_ARCINSTRINFO_H

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

#define GET_INSTRINFO_HEADER
#include "ARCGenInstrInfo.inc"

namespace llvm {

class ARCSubtarget;

class ARCInstrInfo : public ARCGenInstrInfo {
const ARCRegisterInfo RI;
virtual void anchor();

public:
ARCInstrInfo();

const ARCRegisterInfo &getRegisterInfo() const { return RI; }

/// If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
unsigned isLoadFromStackSlot(const MachineInstr &MI,
int &FrameIndex) const override;

/// If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
unsigned isStoreToStackSlot(const MachineInstr &MI,
int &FrameIndex) const override;

unsigned getInstSizeInBytes(const MachineInstr &MI) const override;

bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const override;

unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
const DebugLoc &dl,
int *BytesAdded = nullptr) const override;

unsigned removeBranch(MachineBasicBlock &MBB,
int *BytesRemoved = nullptr) const override;

void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
const DebugLoc &dl, unsigned DestReg, unsigned SrcReg,
bool KillSrc) const override;

void storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI, unsigned SrcReg,
bool isKill, int FrameIndex,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const override;

void loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI, unsigned DestReg,
int FrameIndex, const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const override;

bool
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;

// Emit code before MBBI to load immediate value into physical register Reg.
// Returns an iterator to the new instruction.
MachineBasicBlock::iterator loadImmediate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
unsigned Reg, uint64_t Value) const;
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_ARCINSTRINFO_H
504 changes: 504 additions & 0 deletions llvm/lib/Target/ARC/ARCInstrInfo.td

Large diffs are not rendered by default.

115 changes: 115 additions & 0 deletions llvm/lib/Target/ARC/ARCMCInstLower.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//===- ARCMCInstLower.cpp - ARC 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.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file contains code to lower ARC MachineInstrs to their
/// corresponding MCInst records.
///
//===----------------------------------------------------------------------===//

#include "ARCMCInstLower.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"

using namespace llvm;

ARCMCInstLower::ARCMCInstLower(MCContext *C, AsmPrinter &AsmPrinter)
: Ctx(C), Printer(AsmPrinter) {}

MCOperand ARCMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
MachineOperandType MOTy,
unsigned Offset) const {
MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None;
const MCSymbol *Symbol;

switch (MOTy) {
case MachineOperand::MO_MachineBasicBlock:
Symbol = MO.getMBB()->getSymbol();
break;
case MachineOperand::MO_GlobalAddress:
Symbol = Printer.getSymbol(MO.getGlobal());
Offset += MO.getOffset();
break;
case MachineOperand::MO_BlockAddress:
Symbol = Printer.GetBlockAddressSymbol(MO.getBlockAddress());
Offset += MO.getOffset();
break;
case MachineOperand::MO_ExternalSymbol:
Symbol = Printer.GetExternalSymbolSymbol(MO.getSymbolName());
Offset += MO.getOffset();
break;
case MachineOperand::MO_JumpTableIndex:
Symbol = Printer.GetJTISymbol(MO.getIndex());
break;
case MachineOperand::MO_ConstantPoolIndex:
Symbol = Printer.GetCPISymbol(MO.getIndex());
Offset += MO.getOffset();
break;
default:
llvm_unreachable("<unknown operand type>");
}

assert(Symbol && "Symbol creation failed.\n");
const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Symbol, Kind, *Ctx);

if (!Offset)
return MCOperand::createExpr(MCSym);

// Assume offset is never negative.
assert(Offset > 0);

const MCConstantExpr *OffsetExpr = MCConstantExpr::create(Offset, *Ctx);
const MCBinaryExpr *Add = MCBinaryExpr::createAdd(MCSym, OffsetExpr, *Ctx);
return MCOperand::createExpr(Add);
}

MCOperand ARCMCInstLower::LowerOperand(const MachineOperand &MO,
unsigned Offset) const {
MachineOperandType MOTy = MO.getType();

switch (MOTy) {
default:
llvm_unreachable("unknown operand type");
case MachineOperand::MO_Register:
// Ignore all implicit register operands.
if (MO.isImplicit())
break;
return MCOperand::createReg(MO.getReg());
case MachineOperand::MO_Immediate:
return MCOperand::createImm(MO.getImm() + Offset);
case MachineOperand::MO_MachineBasicBlock:
case MachineOperand::MO_GlobalAddress:
case MachineOperand::MO_ExternalSymbol:
case MachineOperand::MO_JumpTableIndex:
case MachineOperand::MO_ConstantPoolIndex:
case MachineOperand::MO_BlockAddress:
return LowerSymbolOperand(MO, MOTy, Offset);
case MachineOperand::MO_RegisterMask:
break;
}

return {};
}

void ARCMCInstLower::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 = LowerOperand(MO);

if (MCOp.isValid())
OutMI.addOperand(MCOp);
}
}
44 changes: 44 additions & 0 deletions llvm/lib/Target/ARC/ARCMCInstLower.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//===- ARCMCInstLower.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_ARC_ARCMCINSTLOWER_H
#define LLVM_LIB_TARGET_ARC_ARCMCINSTLOWER_H

#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/Support/Compiler.h"

namespace llvm {

class MCContext;
class MCInst;
class MCOperand;
class MachineInstr;
class MachineFunction;
class Mangler;
class AsmPrinter;

/// \brief This class is used to lower an MachineInstr into an MCInst.
class LLVM_LIBRARY_VISIBILITY ARCMCInstLower {
using MachineOperandType = MachineOperand::MachineOperandType;
MCContext *Ctx;
AsmPrinter &Printer;

public:
ARCMCInstLower(MCContext *C, AsmPrinter &asmprinter);
void Lower(const MachineInstr *MI, MCInst &OutMI) const;
MCOperand LowerOperand(const MachineOperand &MO, unsigned offset = 0) const;

private:
MCOperand LowerSymbolOperand(const MachineOperand &MO,
MachineOperandType MOTy, unsigned Offset) const;
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_ARCMCINSTLOWER_H
14 changes: 14 additions & 0 deletions llvm/lib/Target/ARC/ARCMachineFunctionInfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//===- ARCMachineFunctionInfo.cpp - ARC 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.
//
//===----------------------------------------------------------------------===//

#include "ARCMachineFunctionInfo.h"

using namespace llvm;

void ARCFunctionInfo::anchor() {}
64 changes: 64 additions & 0 deletions llvm/lib/Target/ARC/ARCMachineFunctionInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//===- ARCMachineFunctionInfo.h - ARC machine function 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 ARC-specific per-machine-function information.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_ARC_ARCMACHINEFUNCTIONINFO_H
#define LLVM_LIB_TARGET_ARC_ARCMACHINEFUNCTIONINFO_H

#include "llvm/CodeGen/MachineFunction.h"
#include <vector>

namespace llvm {

/// ARCFunctionInfo - This class is derived from MachineFunction private
/// ARC target-specific information for each MachineFunction.
class ARCFunctionInfo : public MachineFunctionInfo {
virtual void anchor();
bool ReturnStackOffsetSet;
int VarArgsFrameIndex;
unsigned VarArgFrameBytes;
unsigned ReturnStackOffset;

public:
ARCFunctionInfo()
: ReturnStackOffsetSet(false), VarArgsFrameIndex(0), VarArgFrameBytes(0),
ReturnStackOffset(-1U), MaxCallStackReq(0) {}

explicit ARCFunctionInfo(MachineFunction &MF)
: ReturnStackOffsetSet(false), VarArgsFrameIndex(0), VarArgFrameBytes(0),
ReturnStackOffset(-1U), MaxCallStackReq(0) {
// Functions are 4-byte (2**2) aligned.
MF.setAlignment(2);
}

~ARCFunctionInfo() {}

void setVarArgsFrameIndex(int off) { VarArgsFrameIndex = off; }
int getVarArgsFrameIndex() const { return VarArgsFrameIndex; }

void setReturnStackOffset(unsigned value) {
assert(!ReturnStackOffsetSet && "Return stack offset set twice");
ReturnStackOffset = value;
ReturnStackOffsetSet = true;
}

unsigned getReturnStackOffset() const {
assert(ReturnStackOffsetSet && "Return stack offset not set");
return ReturnStackOffset;
}

unsigned MaxCallStackReq;
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_ARCMACHINEFUNCTIONINFO_H
233 changes: 233 additions & 0 deletions llvm/lib/Target/ARC/ARCRegisterInfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
//===- ARCRegisterInfo.cpp - ARC 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 ARC implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//

#include "ARCRegisterInfo.h"
#include "ARC.h"
#include "ARCInstrInfo.h"
#include "ARCMachineFunctionInfo.h"
#include "ARCSubtarget.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"

using namespace llvm;

#define DEBUG_TYPE "arc-reg-info"

#define GET_REGINFO_TARGET_DESC
#include "ARCGenRegisterInfo.inc"

static void ReplaceFrameIndex(MachineBasicBlock::iterator II,
const ARCInstrInfo &TII, unsigned Reg,
unsigned FrameReg, int Offset, int StackSize,
int ObjSize, RegScavenger *RS, int SPAdj) {
assert(RS && "Need register scavenger.");
MachineInstr &MI = *II;
MachineBasicBlock &MBB = *MI.getParent();
DebugLoc dl = MI.getDebugLoc();
unsigned BaseReg = FrameReg;
unsigned KillState = 0;
if (MI.getOpcode() == ARC::LD_rs9 && (Offset >= 256 || Offset < -256)) {
// Loads can always be reached with LD_rlimm.
BuildMI(MBB, II, dl, TII.get(ARC::LD_rlimm), Reg)
.addReg(BaseReg)
.addImm(Offset)
.addMemOperand(*MI.memoperands_begin());
MBB.erase(II);
return;
}

if (MI.getOpcode() != ARC::GETFI && (Offset >= 256 || Offset < -256)) {
// We need to use a scratch register to reach the far-away frame indexes.
BaseReg = RS->FindUnusedReg(&ARC::GPR32RegClass);
if (!BaseReg) {
// We can be sure that the scavenged-register slot is within the range
// of the load offset.
const TargetRegisterInfo *TRI =
MBB.getParent()->getSubtarget().getRegisterInfo();
BaseReg = RS->scavengeRegister(&ARC::GPR32RegClass, II, SPAdj);
assert(BaseReg && "Register scavenging failed.");
DEBUG(dbgs() << "Scavenged register " << PrintReg(BaseReg, TRI)
<< " for FrameReg=" << PrintReg(FrameReg, TRI)
<< "+Offset=" << Offset << "\n");
(void)TRI;
RS->setRegUsed(BaseReg);
}
unsigned AddOpc = isUInt<6>(Offset) ? ARC::ADD_rru6 : ARC::ADD_rrlimm;
BuildMI(MBB, II, dl, TII.get(AddOpc))
.addReg(BaseReg, RegState::Define)
.addReg(FrameReg)
.addImm(Offset);
Offset = 0;
KillState = RegState::Kill;
}
switch (MI.getOpcode()) {
case ARC::LD_rs9:
assert((Offset % 4 == 0) && "LD needs 4 byte alignment.");
case ARC::LDH_rs9:
case ARC::LDH_X_rs9:
assert((Offset % 2 == 0) && "LDH needs 2 byte alignment.");
case ARC::LDB_rs9:
case ARC::LDB_X_rs9:
DEBUG(dbgs() << "Building LDFI\n");
BuildMI(MBB, II, dl, TII.get(MI.getOpcode()), Reg)
.addReg(BaseReg, KillState)
.addImm(Offset)
.addMemOperand(*MI.memoperands_begin());
break;
case ARC::ST_rs9:
assert((Offset % 4 == 0) && "ST needs 4 byte alignment.");
case ARC::STH_rs9:
assert((Offset % 2 == 0) && "STH needs 2 byte alignment.");
case ARC::STB_rs9:
DEBUG(dbgs() << "Building STFI\n");
BuildMI(MBB, II, dl, TII.get(MI.getOpcode()))
.addReg(Reg, getKillRegState(MI.getOperand(0).isKill()))
.addReg(BaseReg, KillState)
.addImm(Offset)
.addMemOperand(*MI.memoperands_begin());
break;
case ARC::GETFI:
DEBUG(dbgs() << "Building GETFI\n");
BuildMI(MBB, II, dl,
TII.get(isUInt<6>(Offset) ? ARC::ADD_rru6 : ARC::ADD_rrlimm))
.addReg(Reg, RegState::Define)
.addReg(FrameReg)
.addImm(Offset);
break;
default:
llvm_unreachable("Unhandled opcode.");
}

// Erase old instruction.
MBB.erase(II);
}

ARCRegisterInfo::ARCRegisterInfo() : ARCGenRegisterInfo(ARC::BLINK) {}

bool ARCRegisterInfo::needsFrameMoves(const MachineFunction &MF) {
return MF.getMMI().hasDebugInfo() ||
MF.getFunction()->needsUnwindTableEntry();
}

const MCPhysReg *
ARCRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
return CSR_ARC_SaveList;
}

BitVector ARCRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
BitVector Reserved(getNumRegs());

Reserved.set(ARC::ILINK);
Reserved.set(ARC::SP);
Reserved.set(ARC::GP);
Reserved.set(ARC::R25);
Reserved.set(ARC::BLINK);
Reserved.set(ARC::FP);
return Reserved;
}

bool ARCRegisterInfo::requiresRegisterScavenging(
const MachineFunction &MF) const {
return true;
}

bool ARCRegisterInfo::trackLivenessAfterRegAlloc(
const MachineFunction &MF) const {
return true;
}

bool ARCRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const {
return true;
}

void ARCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, unsigned FIOperandNum,
RegScavenger *RS) const {
assert(SPAdj == 0 && "Unexpected");
MachineInstr &MI = *II;
MachineOperand &FrameOp = MI.getOperand(FIOperandNum);
int FrameIndex = FrameOp.getIndex();

MachineFunction &MF = *MI.getParent()->getParent();
const ARCInstrInfo &TII = *MF.getSubtarget<ARCSubtarget>().getInstrInfo();
const ARCFrameLowering *TFI = getFrameLowering(MF);
int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex);
int ObjSize = MF.getFrameInfo().getObjectSize(FrameIndex);
int StackSize = MF.getFrameInfo().getStackSize();
int LocalFrameSize = MF.getFrameInfo().getLocalFrameSize();

DEBUG(dbgs() << "\nFunction : " << MF.getName() << "\n");
DEBUG(dbgs() << "<--------->\n");
DEBUG(dbgs() << MI << "\n");
DEBUG(dbgs() << "FrameIndex : " << FrameIndex << "\n");
DEBUG(dbgs() << "ObjSize : " << ObjSize << "\n");
DEBUG(dbgs() << "FrameOffset : " << Offset << "\n");
DEBUG(dbgs() << "StackSize : " << StackSize << "\n");
DEBUG(dbgs() << "LocalFrameSize : " << LocalFrameSize << "\n");
(void)LocalFrameSize;

// Special handling of DBG_VALUE instructions.
if (MI.isDebugValue()) {
unsigned FrameReg = getFrameRegister(MF);
MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false /*isDef*/);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
return;
}

// fold constant into offset.
Offset += MI.getOperand(FIOperandNum + 1).getImm();

// TODO: assert based on the load type:
// ldb needs no alignment,
// ldh needs 2 byte alignment
// ld needs 4 byte alignment
DEBUG(dbgs() << "Offset : " << Offset << "\n"
<< "<--------->\n");

unsigned Reg = MI.getOperand(0).getReg();
assert(ARC::GPR32RegClass.contains(Reg) && "Unexpected register operand");

if (!TFI->hasFP(MF)) {
Offset = StackSize + Offset;
if (FrameIndex >= 0)
assert((Offset >= 0 && Offset < StackSize) && "SP Offset not in bounds.");
} else {
if (FrameIndex >= 0) {
assert((Offset < 0 && -Offset <= StackSize) &&
"FP Offset not in bounds.");
}
}
ReplaceFrameIndex(II, TII, Reg, getFrameRegister(MF), Offset, StackSize,
ObjSize, RS, SPAdj);
}

unsigned ARCRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
const ARCFrameLowering *TFI = getFrameLowering(MF);
return TFI->hasFP(MF) ? ARC::FP : ARC::SP;
}

const uint32_t *
ARCRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const {
return CSR_ARC_RegMask;
}
58 changes: 58 additions & 0 deletions llvm/lib/Target/ARC/ARCRegisterInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//===- ARCRegisterInfo.h - ARC 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 ARC implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_ARC_ARCREGISTERINFO_H
#define LLVM_LIB_TARGET_ARC_ARCREGISTERINFO_H

#include "llvm/Target/TargetRegisterInfo.h"

#define GET_REGINFO_HEADER
#include "ARCGenRegisterInfo.inc"

namespace llvm {

class TargetInstrInfo;

struct ARCRegisterInfo : public ARCGenRegisterInfo {
public:
ARCRegisterInfo();

/// Code Generation virtual methods...

const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;

BitVector getReservedRegs(const MachineFunction &MF) const override;

bool requiresRegisterScavenging(const MachineFunction &MF) const override;

bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const override;

bool useFPForScavengingIndex(const MachineFunction &MF) const override;

void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj,
unsigned FIOperandNum,
RegScavenger *RS = nullptr) const override;

const uint32_t *getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const override;

// Debug information queries.
unsigned getFrameRegister(const MachineFunction &MF) const override;

//! Return whether to emit frame moves
static bool needsFrameMoves(const MachineFunction &MF);
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_ARCREGISTERINFO_H
80 changes: 80 additions & 0 deletions llvm/lib/Target/ARC/ARCRegisterInfo.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//===- ARCRegisterInfo.td - ARC 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 ARC register file
//===----------------------------------------------------------------------===//

class ARCReg<string n, list<string> altNames> : Register<n, altNames> {
field bits<6> HwEncoding;
let Namespace = "ARC";
}

// Registers are identified with 6-bit ID numbers.
// Core - 32-bit core registers
class Core<int num, string n, list<string>altNames=[]> : ARCReg<n, altNames> {
let HWEncoding = num;
}

class Status<string n> : ARCReg<n, []> {
}

// Integer registers
def R0 : Core< 0, "%r0">, DwarfRegNum<[0]>;
def R1 : Core< 1, "%r1">, DwarfRegNum<[1]>;
def R2 : Core< 2, "%r2">, DwarfRegNum<[2]>;
def R3 : Core< 3, "%r3">, DwarfRegNum<[3]>;
let CostPerUse=1 in {
def R4 : Core< 4, "%r4">, DwarfRegNum<[4]>;
def R5 : Core< 5, "%r5">, DwarfRegNum<[5]>;
def R6 : Core< 6, "%r6">, DwarfRegNum<[6]>;
def R7 : Core< 7, "%r7">, DwarfRegNum<[7]>;
def R8 : Core< 8, "%r8">, DwarfRegNum<[8]>;
def R9 : Core< 9, "%r9">, DwarfRegNum<[9]>;
def R10 : Core<10, "%r10">, DwarfRegNum<[10]>;
def R11 : Core<11, "%r11">, DwarfRegNum<[11]>;
}
def R12 : Core<12, "%r12">, DwarfRegNum<[12]>;
def R13 : Core<13, "%r13">, DwarfRegNum<[13]>;
def R14 : Core<14, "%r14">, DwarfRegNum<[14]>;
def R15 : Core<15, "%r15">, DwarfRegNum<[15]>;

let CostPerUse=1 in {
def R16 : Core<16, "%r16">, DwarfRegNum<[16]>;
def R17 : Core<17, "%r17">, DwarfRegNum<[17]>;
def R18 : Core<18, "%r18">, DwarfRegNum<[18]>;
def R19 : Core<19, "%r19">, DwarfRegNum<[19]>;
def R20 : Core<20, "%r20">, DwarfRegNum<[20]>;
def R21 : Core<21, "%r21">, DwarfRegNum<[21]>;
def R22 : Core<22, "%r22">, DwarfRegNum<[22]>;
def R23 : Core<23, "%r23">, DwarfRegNum<[23]>;
def R24 : Core<24, "%r24">, DwarfRegNum<[24]>;
def R25 : Core<25, "%r25">, DwarfRegNum<[25]>;
def GP : Core<26, "%gp",["%r26"]>, DwarfRegNum<[26]>;
def FP : Core<27, "%fp", ["%r27"]>, DwarfRegNum<[27]>;
def SP : Core<28, "%sp", ["%r28"]>, DwarfRegNum<[28]>;
def ILINK : Core<29, "%ilink">, DwarfRegNum<[29]>;
def R30 : Core<30, "%r30">, DwarfRegNum<[30]>;
def BLINK: Core<31, "%blink">, DwarfRegNum<[31]>;

def STATUS32 : Status<"status32">, DwarfRegNum<[32]>;
}

// Register classes.
//
def GPR32: RegisterClass<"ARC", [i32], 32,
(add R0, R1, R2, R3,
R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19,
R20, R21, R22, R23, R24, R25, GP, FP, SP, ILINK, R30, BLINK)>;

def SREG : RegisterClass<"ARC", [i32], 1, (add STATUS32)>;

def GPR_S : RegisterClass<"ARC", [i32], 8,
(add R0, R1, R2, R3, R12, R13, R14, R15)>;

31 changes: 31 additions & 0 deletions llvm/lib/Target/ARC/ARCSubtarget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===- ARCSubtarget.cpp - ARC 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 ARC specific subclass of TargetSubtargetInfo.
//
//===----------------------------------------------------------------------===//

#include "ARCSubtarget.h"
#include "ARC.h"
#include "llvm/Support/TargetRegistry.h"

using namespace llvm;

#define DEBUG_TYPE "arc-subtarget"

#define GET_SUBTARGETINFO_TARGET_DESC
#define GET_SUBTARGETINFO_CTOR
#include "ARCGenSubtargetInfo.inc"

void ARCSubtarget::anchor() {}

ARCSubtarget::ARCSubtarget(const Triple &TT, const std::string &CPU,
const std::string &FS, const TargetMachine &TM)
: ARCGenSubtargetInfo(TT, CPU, FS), FrameLowering(*this),
TLInfo(TM, *this) {}
66 changes: 66 additions & 0 deletions llvm/lib/Target/ARC/ARCSubtarget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//===- ARCSubtarget.h - Define Subtarget for the ARC ------------*- 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 ARC specific subclass of TargetSubtargetInfo.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_ARC_ARCSUBTARGET_H
#define LLVM_LIB_TARGET_ARC_ARCSUBTARGET_H

#include "ARCFrameLowering.h"
#include "ARCISelLowering.h"
#include "ARCInstrInfo.h"
#include "llvm/CodeGen/SelectionDAGTargetInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <string>

#define GET_SUBTARGETINFO_HEADER
#include "ARCGenSubtargetInfo.inc"

namespace llvm {

class StringRef;
class TargetMachine;

class ARCSubtarget : public ARCGenSubtargetInfo {
virtual void anchor();
ARCInstrInfo InstrInfo;
ARCFrameLowering FrameLowering;
ARCTargetLowering TLInfo;
SelectionDAGTargetInfo TSInfo;

public:
/// This constructor initializes the data members to match that
/// of the specified triple.
ARCSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS,
const TargetMachine &TM);

/// Parses features string setting specified subtarget options.
/// Definition of function is auto generated by tblgen.
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);

const ARCInstrInfo *getInstrInfo() const override { return &InstrInfo; }
const ARCFrameLowering *getFrameLowering() const override {
return &FrameLowering;
}
const ARCTargetLowering *getTargetLowering() const override {
return &TLInfo;
}
const ARCRegisterInfo *getRegisterInfo() const override {
return &InstrInfo.getRegisterInfo();
}
const SelectionDAGTargetInfo *getSelectionDAGInfo() const override {
return &TSInfo;
}
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_ARCSUBTARGET_H
95 changes: 95 additions & 0 deletions llvm/lib/Target/ARC/ARCTargetMachine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//===- ARCTargetMachine.cpp - Define TargetMachine for ARC ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//

#include "ARCTargetMachine.h"
#include "ARC.h"
#include "ARCTargetTransformInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/Support/TargetRegistry.h"

using namespace llvm;

static Reloc::Model getRelocModel(Optional<Reloc::Model> RM) {
if (!RM.hasValue())
return Reloc::Static;
return *RM;
}

static CodeModel::Model getEffectiveCodeModel(Optional<CodeModel::Model> CM) {
if (CM)
return *CM;
return CodeModel::Small;
}

/// ARCTargetMachine ctor - Create an ILP32 architecture model
ARCTargetMachine::ARCTargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS,
const TargetOptions &Options,
Optional<Reloc::Model> RM,
Optional<CodeModel::Model> CM,
CodeGenOpt::Level OL, bool JIT)
: LLVMTargetMachine(T,
"e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"f32:32:32-i64:32-f64:32-a:0:32-n32",
TT, CPU, FS, Options, getRelocModel(RM),
getEffectiveCodeModel(CM), OL),
TLOF(make_unique<TargetLoweringObjectFileELF>()),
Subtarget(TT, CPU, FS, *this) {
initAsmInfo();
}

ARCTargetMachine::~ARCTargetMachine() = default;

namespace {

/// ARC Code Generator Pass Configuration Options.
class ARCPassConfig : public TargetPassConfig {
public:
ARCPassConfig(ARCTargetMachine &TM, PassManagerBase &PM)
: TargetPassConfig(TM, PM) {}

ARCTargetMachine &getARCTargetMachine() const {
return getTM<ARCTargetMachine>();
}

bool addInstSelector() override;
void addPreEmitPass() override;
void addPreRegAlloc() override;
};

} // end anonymous namespace

TargetPassConfig *ARCTargetMachine::createPassConfig(PassManagerBase &PM) {
return new ARCPassConfig(*this, PM);
}

bool ARCPassConfig::addInstSelector() {
addPass(createARCISelDag(getARCTargetMachine(), getOptLevel()));
return false;
}

void ARCPassConfig::addPreEmitPass() { addPass(createARCBranchFinalizePass()); }

void ARCPassConfig::addPreRegAlloc() { addPass(createARCExpandPseudosPass()); }

// Force static initialization.
extern "C" void LLVMInitializeARCTarget() {
RegisterTargetMachine<ARCTargetMachine> X(getTheARCTarget());
}

TargetIRAnalysis ARCTargetMachine::getTargetIRAnalysis() {
return TargetIRAnalysis([this](const Function &F) {
return TargetTransformInfo(ARCTTIImpl(this, F));
});
}
51 changes: 51 additions & 0 deletions llvm/lib/Target/ARC/ARCTargetMachine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//===- ARCTargetMachine.h - Define TargetMachine for ARC --------*- 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 ARC specific subclass of TargetMachine.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_ARC_ARCTARGETMACHINE_H
#define LLVM_LIB_TARGET_ARC_ARCTARGETMACHINE_H

#include "ARCSubtarget.h"
#include "llvm/Target/TargetMachine.h"

namespace llvm {

class TargetPassConfig;

class ARCTargetMachine : public LLVMTargetMachine {
std::unique_ptr<TargetLoweringObjectFile> TLOF;
ARCSubtarget Subtarget;

public:
ARCTargetMachine(const Target &T, const Triple &TT, StringRef CPU,
StringRef FS, const TargetOptions &Options,
Optional<Reloc::Model> RM, Optional<CodeModel::Model> CM,
CodeGenOpt::Level OL, bool JIT);
~ARCTargetMachine() override;

const ARCSubtarget *getSubtargetImpl() const { return &Subtarget; }
const ARCSubtarget *getSubtargetImpl(const Function &) const override {
return &Subtarget;
}

// Pass Pipeline Configuration
TargetPassConfig *createPassConfig(PassManagerBase &PM) override;

TargetIRAnalysis getTargetIRAnalysis() override;
TargetLoweringObjectFile *getObjFileLowering() const override {
return TLOF.get();
}
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_ARCTARGETMACHINE_H
25 changes: 25 additions & 0 deletions llvm/lib/Target/ARC/ARCTargetStreamer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===- ARCTargetStreamer.h - ARC Target Streamer ----------------*- 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_ARC_ARCTARGETSTREAMER_H
#define LLVM_LIB_TARGET_ARC_ARCTARGETSTREAMER_H

#include "llvm/MC/MCStreamer.h"

namespace llvm {

class ARCTargetStreamer : public MCTargetStreamer {
public:
ARCTargetStreamer(MCStreamer &S);
~ARCTargetStreamer() override;
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_ARCTARGETSTREAMER_H
55 changes: 55 additions & 0 deletions llvm/lib/Target/ARC/ARCTargetTransformInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//===- ARCTargetTransformInfo.h - ARC specific TTI --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// \file
// This file contains a TargetTransformInfo::Concept conforming object specific
// to the ARC 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_ARC_ARCTARGETTRANSFORMINFO_H
#define LLVM_LIB_TARGET_ARC_ARCTARGETTRANSFORMINFO_H

#include "ARC.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/CodeGen/BasicTTIImpl.h"

namespace llvm {

class ARCSubtarget;
class ARCTargetLowering;
class ARCTargetMachine;

class ARCTTIImpl : public BasicTTIImplBase<ARCTTIImpl> {
using BaseT = BasicTTIImplBase<ARCTTIImpl>;
friend BaseT;

const ARCSubtarget *ST;
const ARCTargetLowering *TLI;

const ARCSubtarget *getST() const { return ST; }
const ARCTargetLowering *getTLI() const { return TLI; }

public:
explicit ARCTTIImpl(const ARCTargetMachine *TM, const Function &F)
: BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl()),
TLI(ST->getTargetLowering()) {}

// Provide value semantics. MSVC requires that we spell all of these out.
ARCTTIImpl(const ARCTTIImpl &Arg)
: BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
ARCTTIImpl(ARCTTIImpl &&Arg)
: BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
TLI(std::move(Arg.TLI)) {}
};

} // end namespace llvm

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

tablegen(LLVM ARCGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM ARCGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM ARCGenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM ARCGenAsmWriter.inc -gen-asm-writer)
tablegen(LLVM ARCGenDAGISel.inc -gen-dag-isel)
tablegen(LLVM ARCGenCallingConv.inc -gen-callingconv)
tablegen(LLVM ARCGenSubtargetInfo.inc -gen-subtarget)
add_public_tablegen_target(ARCCommonTableGen)

add_llvm_target(ARCCodeGen
ARCAsmPrinter.cpp
ARCBranchFinalize.cpp
ARCExpandPseudos.cpp
ARCFrameLowering.cpp
ARCInstrInfo.cpp
ARCISelDAGToDAG.cpp
ARCISelLowering.cpp
ARCMachineFunctionInfo.cpp
ARCMCInstLower.cpp
ARCRegisterInfo.cpp
ARCSubtarget.cpp
ARCTargetMachine.cpp
)

add_subdirectory(InstPrinter)
add_subdirectory(TargetInfo)
add_subdirectory(MCTargetDesc)
add_subdirectory(Disassembler)
298 changes: 298 additions & 0 deletions llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
//===- ARCDisassembler.cpp - Disassembler for ARC ---------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file is part of the ARC Disassembler.
///
//===----------------------------------------------------------------------===//

#include "ARC.h"
#include "ARCRegisterInfo.h"
#include "MCTargetDesc/ARCMCTargetDesc.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCFixedLenDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/TargetRegistry.h"

using namespace llvm;

#define DEBUG_TYPE "arc-disassembler"

using DecodeStatus = MCDisassembler::DecodeStatus;

namespace {

/// \brief A disassembler class for ARC.
class ARCDisassembler : public MCDisassembler {
public:
std::unique_ptr<MCInstrInfo const> const MCII;

ARCDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
MCInstrInfo const *MCII)
: MCDisassembler(STI, Ctx), MCII(MCII) {}

DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &VStream,
raw_ostream &CStream) const override;
};

} // end anonymous namespace

static bool readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
uint64_t &Size, uint32_t &Insn) {
Size = 4;
// Read 2 16-bit values, but swap hi/lo parts.
Insn =
(Bytes[0] << 16) | (Bytes[1] << 24) | (Bytes[2] << 0) | (Bytes[3] << 8);
return true;
}

static bool readInstruction64(ArrayRef<uint8_t> Bytes, uint64_t Address,
uint64_t &Size, uint64_t &Insn) {
Size = 8;
Insn = ((uint64_t)Bytes[0] << 16) | ((uint64_t)Bytes[1] << 24) |
((uint64_t)Bytes[2] << 0) | ((uint64_t)Bytes[3] << 8) |
((uint64_t)Bytes[4] << 48) | ((uint64_t)Bytes[5] << 56) |
((uint64_t)Bytes[6] << 32) | ((uint64_t)Bytes[7] << 40);
return true;
}

static bool readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
uint64_t &Size, uint32_t &Insn) {
Size = 2;
Insn = (Bytes[0] << 0) | (Bytes[1] << 8);
return true;
}

static MCDisassembler::DecodeStatus DecodeS12Operand(MCInst &, unsigned,
uint64_t, const void *);

static MCDisassembler::DecodeStatus DecodeS9Operand(MCInst &, unsigned,
uint64_t, const void *);

static MCDisassembler::DecodeStatus
DecodeBranchTargetS9(MCInst &, unsigned, uint64_t, const void *);

static MCDisassembler::DecodeStatus
DecodeBranchTargetS21(MCInst &, unsigned, uint64_t, const void *);

static MCDisassembler::DecodeStatus
DecodeBranchTargetS25(MCInst &, unsigned, uint64_t, const void *);

static MCDisassembler::DecodeStatus DecodeMEMrs9(MCInst &, unsigned, uint64_t,
const void *);

static MCDisassembler::DecodeStatus
DecodeLdLImmInstruction(MCInst &, uint64_t, uint64_t, const void *);

static MCDisassembler::DecodeStatus
DecodeStLImmInstruction(MCInst &, uint64_t, uint64_t, const void *);

static MCDisassembler::DecodeStatus
DecodeLdRLImmInstruction(MCInst &, uint64_t, uint64_t, const void *);

static const uint16_t GPR32DecoderTable[] = {
ARC::R0, ARC::R1, ARC::R2, ARC::R3, ARC::R4, ARC::R5, ARC::R6,
ARC::R7, ARC::R8, ARC::R9, ARC::R10, ARC::R11, ARC::R12, ARC::R13,
ARC::R14, ARC::R15, ARC::R16, ARC::R17, ARC::R18, ARC::R19, ARC::R20,
ARC::R21, ARC::R22, ARC::R23, ARC::R24, ARC::R25, ARC::GP, ARC::FP,
ARC::SP, ARC::ILINK, ARC::R30, ARC::BLINK};

static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo >= 32) {
DEBUG(dbgs() << "Not a GPR32 register.");
return MCDisassembler::Fail;
}
unsigned Reg = GPR32DecoderTable[RegNo];
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}

#include "ARCGenDisassemblerTables.inc"

static unsigned decodeCField(unsigned Insn) {
return fieldFromInstruction(Insn, 6, 6);
}

static unsigned decodeBField(unsigned Insn) {
return (fieldFromInstruction(Insn, 12, 3) << 3) |
fieldFromInstruction(Insn, 24, 3);
}

static unsigned decodeAField(unsigned Insn) {
return fieldFromInstruction(Insn, 0, 6);
}

static MCDisassembler::DecodeStatus
DecodeMEMrs9(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Dec) {
// We have the 9-bit immediate in the low bits, 6-bit register in high bits.
unsigned S9 = Insn & 0x1ff;
unsigned R = (Insn & (0x7fff & ~0x1ff)) >> 9;
DecodeGPR32RegisterClass(Inst, R, Address, Dec);
Inst.addOperand(MCOperand::createImm(SignExtend32<9>(S9)));
return MCDisassembler::Success;
}

static MCDisassembler::DecodeStatus DecodeS9Operand(MCInst &Inst,
unsigned InsnS9,
uint64_t Address,
const void *Decoder) {
Inst.addOperand(MCOperand::createImm(SignExtend32<9>(0x1ff & InsnS9)));
return MCDisassembler::Success;
}

static MCDisassembler::DecodeStatus DecodeS12Operand(MCInst &Inst,
unsigned InsnS12,
uint64_t Address,
const void *Decoder) {
Inst.addOperand(MCOperand::createImm(SignExtend32<12>(0xfff & InsnS12)));
return MCDisassembler::Success;
}

static MCDisassembler::DecodeStatus DecodeBranchTargetS9(MCInst &Inst,
unsigned S,
uint64_t Address,
const void *Decoder) {
Inst.addOperand(MCOperand::createImm(SignExtend32<9>(S)));
return MCDisassembler::Success;
}

static MCDisassembler::DecodeStatus DecodeBranchTargetS21(MCInst &Inst,
unsigned S,
uint64_t Address,
const void *Decoder) {
Inst.addOperand(MCOperand::createImm(SignExtend32<21>(S)));
return MCDisassembler::Success;
}

static MCDisassembler::DecodeStatus DecodeBranchTargetS25(MCInst &Inst,
unsigned S,
uint64_t Address,
const void *Decoder) {
Inst.addOperand(MCOperand::createImm(SignExtend32<25>(S)));
return MCDisassembler::Success;
}

static MCDisassembler::DecodeStatus
DecodeStLImmInstruction(MCInst &Inst, uint64_t Insn, uint64_t Address,
const void *Decoder) {
unsigned SrcC, DstB, LImm;
DstB = decodeBField(Insn);
if (DstB != 62) {
DEBUG(dbgs() << "Decoding StLImm found non-limm register.");
return MCDisassembler::Fail;
}
SrcC = decodeCField(Insn);
DecodeGPR32RegisterClass(Inst, SrcC, Address, Decoder);
LImm = (Insn >> 32);
Inst.addOperand(MCOperand::createImm(LImm));
Inst.addOperand(MCOperand::createImm(0));
return MCDisassembler::Success;
}

static MCDisassembler::DecodeStatus
DecodeLdLImmInstruction(MCInst &Inst, uint64_t Insn, uint64_t Address,
const void *Decoder) {
unsigned DstA, SrcB, LImm;
DEBUG(dbgs() << "Decoding LdLImm:\n");
SrcB = decodeBField(Insn);
if (SrcB != 62) {
DEBUG(dbgs() << "Decoding LdLImm found non-limm register.");
return MCDisassembler::Fail;
}
DstA = decodeAField(Insn);
DecodeGPR32RegisterClass(Inst, DstA, Address, Decoder);
LImm = (Insn >> 32);
Inst.addOperand(MCOperand::createImm(LImm));
Inst.addOperand(MCOperand::createImm(0));
return MCDisassembler::Success;
}

static MCDisassembler::DecodeStatus
DecodeLdRLImmInstruction(MCInst &Inst, uint64_t Insn, uint64_t Address,
const void *Decoder) {
unsigned DstA, SrcB;
DEBUG(dbgs() << "Decoding LdRLimm\n");
DstA = decodeAField(Insn);
DecodeGPR32RegisterClass(Inst, DstA, Address, Decoder);
SrcB = decodeBField(Insn);
DecodeGPR32RegisterClass(Inst, SrcB, Address, Decoder);
if (decodeCField(Insn) != 62) {
DEBUG(dbgs() << "Decoding LdRLimm found non-limm register.");
return MCDisassembler::Fail;
}
Inst.addOperand(MCOperand::createImm((uint32_t)(Insn >> 32)));
return MCDisassembler::Success;
}

MCDisassembler::DecodeStatus ARCDisassembler::getInstruction(
MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &vStream, raw_ostream &cStream) const {
MCDisassembler::DecodeStatus Result;
if (Bytes.size() < 2) {
Size = 0;
return Fail;
}
uint8_t DecodeByte = (Bytes[1] & 0xF7) >> 3;
// 0x00 -> 0x07 are 32-bit instructions.
// 0x08 -> 0x1F are 16-bit instructions.
if (DecodeByte < 0x08) {
// 32-bit instruction.
if (Bytes.size() < 4) {
// Did we decode garbage?
Size = 0;
return Fail;
}
if (Bytes.size() >= 8) {
// Attempt to decode 64-bit instruction.
uint64_t Insn64;
if (!readInstruction64(Bytes, Address, Size, Insn64))
return Fail;
Result =
decodeInstruction(DecoderTable64, Instr, Insn64, Address, this, STI);
if (Result == MCDisassembler::Success) {
DEBUG(dbgs() << "Successfully decoded 64-bit instruction.");
return MCDisassembler::Success;
}
DEBUG(dbgs() << "Not a 64-bit instruction, falling back to 32-bit.");
}
uint32_t Insn32;
if (!readInstruction32(Bytes, Address, Size, Insn32)) {
return Fail;
}
// Calling the auto-generated decoder function.
return decodeInstruction(DecoderTable32, Instr, Insn32, Address, this, STI);
}

// 16-bit instruction.
uint32_t Insn16;
if (!readInstruction16(Bytes, Address, Size, Insn16)) {
return Fail;
}
// Calling the auto-generated decoder function.
return decodeInstruction(DecoderTable16, Instr, Insn16, Address, this, STI);
}

static MCDisassembler *createARCDisassembler(const Target &T,
const MCSubtargetInfo &STI,
MCContext &Ctx) {
return new ARCDisassembler(STI, Ctx, T.createMCInstrInfo());
}

extern "C" void LLVMInitializeARCDisassembler() {
// Register the disassembler.
TargetRegistry::RegisterMCDisassembler(getTheARCTarget(),
createARCDisassembler);
}
3 changes: 3 additions & 0 deletions llvm/lib/Target/ARC/Disassembler/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_llvm_library(LLVMARCDisassembler
ARCDisassembler.cpp
)
23 changes: 23 additions & 0 deletions llvm/lib/Target/ARC/Disassembler/LLVMBuild.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
;===- ./lib/Target/ARC/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 = ARCDisassembler
parent = ARC
required_libraries = MCDisassembler Support ARCInfo
add_to_library_groups = ARC
166 changes: 166 additions & 0 deletions llvm/lib/Target/ARC/InstPrinter/ARCInstPrinter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
//===- ARCInstPrinter.cpp - ARC MCInst to assembly 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 an ARC MCInst to a .s file.
//
//===----------------------------------------------------------------------===//

#include "ARCInstPrinter.h"
#include "MCTargetDesc/ARCInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

#define DEBUG_TYPE "asm-printer"

#include "ARCGenAsmWriter.inc"

static const char *ARCBRCondCodeToString(ARCCC::BRCondCode BRCC) {
switch (BRCC) {
case ARCCC::BREQ:
return "eq";
case ARCCC::BRNE:
return "ne";
case ARCCC::BRLT:
return "lt";
case ARCCC::BRGE:
return "ge";
case ARCCC::BRLO:
return "lo";
case ARCCC::BRHS:
return "hs";
default:
llvm_unreachable("Unhandled ARCCC::BRCondCode");
}
}

static const char *ARCCondCodeToString(ARCCC::CondCode CC) {
switch (CC) {
case ARCCC::EQ:
return "eq";
case ARCCC::NE:
return "ne";
case ARCCC::P:
return "p";
case ARCCC::N:
return "n";
case ARCCC::HS:
return "hs";
case ARCCC::LO:
return "lo";
case ARCCC::GT:
return "gt";
case ARCCC::GE:
return "ge";
case ARCCC::LT:
return "lt";
case ARCCC::LE:
return "le";
case ARCCC::HI:
return "hi";
case ARCCC::LS:
return "ls";
case ARCCC::PNZ:
return "pnz";
case ARCCC::AL:
return "al";
case ARCCC::NZ:
return "nz";
case ARCCC::Z:
return "z";
}
llvm_unreachable("Unhandled ARCCC::CondCode");
}

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

void ARCInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
StringRef Annot, const MCSubtargetInfo &STI) {
printInstruction(MI, O);
printAnnotation(O, Annot);
}

static void printExpr(const MCExpr *Expr, const MCAsmInfo *MAI,
raw_ostream &OS) {
int Offset = 0;
const MCSymbolRefExpr *SRE;

if (const auto *BE = dyn_cast<MCBinaryExpr>(Expr)) {
SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS());
const auto *CE = dyn_cast<MCConstantExpr>(BE->getRHS());
assert(SRE && CE && "Binary expression must be sym+const.");
Offset = CE->getValue();
} else {
SRE = dyn_cast<MCSymbolRefExpr>(Expr);
assert(SRE && "Unexpected MCExpr type.");
}
assert(SRE->getKind() == MCSymbolRefExpr::VK_None);

// Symbols are prefixed with '@'
OS << '@';
SRE->getSymbol().print(OS, MAI);

if (Offset) {
if (Offset > 0)
OS << '+';
OS << Offset;
}
}

void ARCInstPrinter::printOperand(const MCInst *MI, unsigned OpNum,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNum);
if (Op.isReg()) {
printRegName(O, Op.getReg());
return;
}

if (Op.isImm()) {
O << Op.getImm();
return;
}

assert(Op.isExpr() && "unknown operand kind in printOperand");
printExpr(Op.getExpr(), &MAI, O);
}

void ARCInstPrinter::printMemOperandRI(const MCInst *MI, unsigned OpNum,
raw_ostream &O) {
const MCOperand &base = MI->getOperand(OpNum);
const MCOperand &offset = MI->getOperand(OpNum + 1);
assert(base.isReg() && "Base should be register.");
assert(offset.isImm() && "Offset should be immediate.");
printRegName(O, base.getReg());
O << "," << offset.getImm();
}

void ARCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum,
raw_ostream &O) {

const MCOperand &Op = MI->getOperand(OpNum);
assert(Op.isImm() && "Predicate operand is immediate.");
O << ARCCondCodeToString((ARCCC::CondCode)Op.getImm());
}

void ARCInstPrinter::printBRCCPredicateOperand(const MCInst *MI, unsigned OpNum,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNum);
assert(Op.isImm() && "Predicate operand is immediate.");
O << ARCBRCondCodeToString((ARCCC::BRCondCode)Op.getImm());
}
46 changes: 46 additions & 0 deletions llvm/lib/Target/ARC/InstPrinter/ARCInstPrinter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===- ARCInstPrinter.h - Convert ARC MCInst to assembly syntax -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file contains the declaration of the ARCInstPrinter class,
/// which is used to print ARC MCInst to a .s file.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_ARC_INSTPRINTER_ARCINSTPRINTER_H
#define LLVM_LIB_TARGET_ARC_INSTPRINTER_ARCINSTPRINTER_H

#include "llvm/MC/MCInstPrinter.h"

namespace llvm {

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

// Autogenerated by tblgen.
void printInstruction(const MCInst *MI, raw_ostream &O);
static const char *getRegisterName(unsigned RegNo);

void printRegName(raw_ostream &OS, unsigned RegNo) const override;
void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
const MCSubtargetInfo &STI) override;

private:
void printMemOperandRI(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printPredicateOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printBRCCPredicateOperand(const MCInst *MI, unsigned OpNum,
raw_ostream &O);
};
} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_INSTPRINTER_ARCINSTPRINTER_H
3 changes: 3 additions & 0 deletions llvm/lib/Target/ARC/InstPrinter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_llvm_library(LLVMARCAsmPrinter
ARCInstPrinter.cpp
)
23 changes: 23 additions & 0 deletions llvm/lib/Target/ARC/InstPrinter/LLVMBuild.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
;===- ./lib/Target/ARC/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 = ARCAsmPrinter
parent = ARC
required_libraries = MC Support
add_to_library_groups = ARC
45 changes: 45 additions & 0 deletions llvm/lib/Target/ARC/LLVMBuild.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
;===- ./lib/Target/ARC/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 = Disassembler InstPrinter MCTargetDesc TargetInfo

[component_0]
type = TargetGroup
name = ARC
parent = Target
has_asmprinter = 1
has_disassembler = 1

[component_1]
type = Library
name = ARCCodeGen
parent = ARC
required_libraries =
Analysis
AsmPrinter
CodeGen
Core
MC
SelectionDAG
Support
Target
TransformUtils
ARCAsmPrinter
ARCDesc
ARCInfo
add_to_library_groups = ARC
57 changes: 57 additions & 0 deletions llvm/lib/Target/ARC/MCTargetDesc/ARCInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//===- ARCInfo.h - Additional ARC 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 contains small standalone helper functions and enum definitions for
// the ARC target useful for the compiler back-end and the MC libraries.
// As such, it deliberately does not include references to LLVM core
// code gen types, passes, etc..
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCINFO_H
#define LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCINFO_H

namespace llvm {

// Enums corresponding to ARC condition codes
namespace ARCCC {

enum CondCode {
AL = 0x0,
EQ = 0x1,
NE = 0x2,
P = 0x3,
N = 0x4,
LO = 0x5,
HS = 0x6,
GT = 0x9,
GE = 0xa,
LT = 0xb,
LE = 0xc,
HI = 0xd,
LS = 0xe,
PNZ = 0xf,
Z = 0x11, // Low 4-bits = EQ
NZ = 0x12 // Low 4-bits = NE
};

enum BRCondCode {
BREQ = 0x0,
BRNE = 0x1,
BRLT = 0x2,
BRGE = 0x3,
BRLO = 0x4,
BRHS = 0x5
};

} // end namespace ARCCC

} // end namespace llvm

#endif
32 changes: 32 additions & 0 deletions llvm/lib/Target/ARC/MCTargetDesc/ARCMCAsmInfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===- ARCMCAsmInfo.cpp - ARC asm properties --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ARCMCAsmInfo.h"
using namespace llvm;

void ARCMCAsmInfo::anchor() {}

ARCMCAsmInfo::ARCMCAsmInfo(const Triple &TT) {
SupportsDebugInformation = true;
Data16bitsDirective = "\t.short\t";
Data32bitsDirective = "\t.word\t";
Data64bitsDirective = nullptr;
ZeroDirective = "\t.space\t";
CommentString = ";";

UsesELFSectionDirectiveForBSS = true;
AllowAtInName = true;
HiddenVisibilityAttr = MCSA_Invalid;
HiddenDeclarationVisibilityAttr = MCSA_Invalid;
ProtectedVisibilityAttr = MCSA_Invalid;

// Debug
ExceptionsType = ExceptionHandling::DwarfCFI;
DwarfRegNumForCFI = true;
}
32 changes: 32 additions & 0 deletions llvm/lib/Target/ARC/MCTargetDesc/ARCMCAsmInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===- ARCMCAsmInfo.h - ARC 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 ARCMCAsmInfo class.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCMCASMINFO_H
#define LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCMCASMINFO_H

#include "llvm/MC/MCAsmInfoELF.h"

namespace llvm {

class Triple;

class ARCMCAsmInfo : public MCAsmInfoELF {
void anchor() override;

public:
explicit ARCMCAsmInfo(const Triple &TT);
};

} // end namespace llvm

#endif // LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCMCASMINFO_H
Loading