[ARC] Add ARC backend.

Add the ARC backend as an experimental target to lib/Target.
Reviewed at: https://reviews.llvm.org/D36331

llvm-svn: 311667
This commit is contained in:
Pete Couperus 2017-08-24 15:40:33 +00:00
parent 94f045b3a9
commit 7fc741759e
61 changed files with 6360 additions and 0 deletions

View File

@ -44,6 +44,10 @@ N: Greg Clayton
E: clayborg@gmail.com
D: LLDB
N: Pete Couperus
E: petecoup@synopsys.com
D: ARC backend (lib/Target/ARC/*)
N: Sanjoy Das
E: sanjoy@playingwithpointers.com
D: IndVar Simplify, Scalar Evolution

View File

@ -50,6 +50,7 @@ public:
armeb, // ARM (big endian): armeb
aarch64, // AArch64 (little endian): aarch64
aarch64_be, // AArch64 (big endian): aarch64_be
arc, // ARC: Synopsys ARC
avr, // AVR: Atmel AVR microcontroller
bpfel, // eBPF or extended BPF or 64-bit BPF (little endian)
bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian)

View File

@ -25,6 +25,7 @@ StringRef Triple::getArchTypeName(ArchType Kind) {
case aarch64_be: return "aarch64_be";
case arm: return "arm";
case armeb: return "armeb";
case arc: return "arc";
case avr: return "avr";
case bpfel: return "bpfel";
case bpfeb: return "bpfeb";
@ -83,6 +84,8 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) {
case aarch64:
case aarch64_be: return "aarch64";
case arc: return "arc";
case arm:
case armeb:
case thumb:
@ -255,6 +258,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) {
return StringSwitch<Triple::ArchType>(Name)
.Case("aarch64", aarch64)
.Case("aarch64_be", aarch64_be)
.Case("arc", arc)
.Case("arm64", aarch64) // "arm64" is an alias for "aarch64"
.Case("arm", arm)
.Case("armeb", armeb)
@ -384,6 +388,7 @@ static Triple::ArchType parseArch(StringRef ArchName) {
.Case("xscaleeb", Triple::armeb)
.Case("aarch64", Triple::aarch64)
.Case("aarch64_be", Triple::aarch64_be)
.Case("arc", Triple::arc)
.Case("arm64", Triple::aarch64)
.Case("arm", Triple::arm)
.Case("armeb", Triple::armeb)
@ -620,6 +625,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
return Triple::ELF;
case Triple::aarch64_be:
case Triple::arc:
case Triple::amdgcn:
case Triple::amdil:
case Triple::amdil64:
@ -1173,6 +1179,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) {
case llvm::Triple::msp430:
return 16;
case llvm::Triple::arc:
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::hexagon:
@ -1256,6 +1263,7 @@ Triple Triple::get32BitArchVariant() const {
case Triple::amdil:
case Triple::hsail:
case Triple::spir:
case Triple::arc:
case Triple::arm:
case Triple::armeb:
case Triple::hexagon:
@ -1306,6 +1314,7 @@ Triple Triple::get64BitArchVariant() const {
Triple T(*this);
switch (getArch()) {
case Triple::UnknownArch:
case Triple::arc:
case Triple::avr:
case Triple::hexagon:
case Triple::kalimba:

33
lib/Target/ARC/ARC.h Normal file
View File

@ -0,0 +1,33 @@
//===- ARC.h - Top-level interface for ARC 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
// ARC back-end.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_ARC_ARC_H
#define LLVM_LIB_TARGET_ARC_ARC_H
#include "MCTargetDesc/ARCMCTargetDesc.h"
#include "llvm/Target/TargetMachine.h"
namespace llvm {
class FunctionPass;
class ARCTargetMachine;
FunctionPass *createARCISelDag(ARCTargetMachine &TM,
CodeGenOpt::Level OptLevel);
FunctionPass *createARCExpandPseudosPass();
FunctionPass *createARCBranchFinalizePass();
} // end namespace llvm
#endif // LLVM_LIB_TARGET_ARC_ARC_H

25
lib/Target/ARC/ARC.td Normal file
View File

@ -0,0 +1,25 @@
//===- ARC.td - Describe the ARC Target Machine ------------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
include "llvm/Target/Target.td"
include "ARCRegisterInfo.td"
include "ARCInstrInfo.td"
include "ARCCallingConv.td"
def ARCInstrInfo : InstrInfo;
class Proc<string Name, list<SubtargetFeature> Features>
: Processor<Name, NoItineraries, Features>;
def : Proc<"generic", []>;
def ARC : Target {
let InstructionSet = ARCInstrInfo;
}

View File

@ -0,0 +1,83 @@
//===- ARCAsmPrinter.cpp - ARC LLVM assembly writer -------------*- 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 a printer that converts from our internal representation
// of machine-dependent LLVM code to GNU format ARC assembly language.
//
//===----------------------------------------------------------------------===//
#include "ARC.h"
#include "ARCInstrInfo.h"
#include "ARCMCInstLower.h"
#include "ARCSubtarget.h"
#include "ARCTargetMachine.h"
#include "ARCTargetStreamer.h"
#include "InstPrinter/ARCInstPrinter.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbolELF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include <algorithm>
using namespace llvm;
#define DEBUG_TYPE "asm-printer"
namespace {
class ARCAsmPrinter : public AsmPrinter {
ARCMCInstLower MCInstLowering;
ARCTargetStreamer &getTargetStreamer();
public:
explicit ARCAsmPrinter(TargetMachine &TM,
std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)),
MCInstLowering(&OutContext, *this) {}
StringRef getPassName() const override { return "ARC Assembly Printer"; }
void EmitInstruction(const MachineInstr *MI) override;
};
} // end anonymous namespace
ARCTargetStreamer &ARCAsmPrinter::getTargetStreamer() {
return static_cast<ARCTargetStreamer &>(*OutStreamer->getTargetStreamer());
}
void ARCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
SmallString<128> Str;
raw_svector_ostream O(Str);
switch (MI->getOpcode()) {
case ARC::DBG_VALUE:
llvm_unreachable("Should be handled target independently");
break;
}
MCInst TmpInst;
MCInstLowering.Lower(MI, TmpInst);
EmitToStreamer(*OutStreamer, TmpInst);
}
// Force static initialization.
extern "C" void LLVMInitializeARCAsmPrinter() {
RegisterAsmPrinter<ARCAsmPrinter> X(getTheARCTarget());
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,472 @@
//===- ARCFrameLowering.cpp - ARC Frame 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 TargetFrameLowering class.
//
//===----------------------------------------------------------------------===//
#include "ARCFrameLowering.h"
#include "ARCMachineFunctionInfo.h"
#include "ARCSubtarget.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetRegisterInfo.h"
#define DEBUG_TYPE "arc-frame-lowering"
using namespace llvm;
static cl::opt<bool>
UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden,
cl::desc("Use arc callee save/restore functions"),
cl::init(true));
static const char *store_funclet_name[] = {
"__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18",
"__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22",
"__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25",
};
static const char *load_funclet_name[] = {
"__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18",
"__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22",
"__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25",
};
static void generateStackAdjustment(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const ARCInstrInfo &TII, DebugLoc dl,
int Amount, int StackPtr) {
unsigned AdjOp;
if (!Amount)
return;
bool Positive;
unsigned AbsAmount;
if (Amount < 0) {
AbsAmount = -Amount;
Positive = false;
} else {
AbsAmount = Amount;
Positive = true;
}
DEBUG(dbgs() << "Internal: adjust stack by: " << Amount << "," << AbsAmount
<< "\n");
assert((AbsAmount % 4 == 0) && "Stack adjustments must be 4-byte aligned.");
if (isUInt<6>(AbsAmount))
AdjOp = Positive ? ARC::ADD_rru6 : ARC::SUB_rru6;
else
AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr)
.addReg(StackPtr)
.addImm(AbsAmount);
}
static unsigned
determineLastCalleeSave(const std::vector<CalleeSavedInfo> &CSI) {
unsigned Last = 0;
for (auto Reg : CSI) {
assert(Reg.getReg() >= ARC::R13 && Reg.getReg() <= ARC::R25 &&
"Unexpected callee saved reg.");
if (Reg.getReg() > Last)
Last = Reg.getReg();
}
return Last;
}
void ARCFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
DEBUG(dbgs() << "Determine Callee Saves: " << MF.getFunction()->getName()
<< "\n");
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
SavedRegs.set(ARC::BLINK);
}
void ARCFrameLowering::adjustStackToMatchRecords(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
bool Allocate) const {
MachineFunction &MF = *MBB.getParent();
int ScalarAlloc = MF.getFrameInfo().getStackSize();
if (Allocate) {
// Allocate by adjusting by the negative of what the record holder tracked
// it tracked a positive offset in a downward growing stack.
ScalarAlloc = -ScalarAlloc;
}
generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(),
ScalarAlloc, ARC::SP);
}
/// Insert prolog code into the function.
/// For ARC, this inserts a call to a function that puts required callee saved
/// registers onto the stack, when enough callee saved registers are required.
void ARCFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
DEBUG(dbgs() << "Emit Prologue: " << MF.getFunction()->getName() << "\n");
auto *AFI = MF.getInfo<ARCFunctionInfo>();
MachineModuleInfo &MMI = MF.getMMI();
MCContext &Context = MMI.getContext();
const MCRegisterInfo *MRI = Context.getRegisterInfo();
const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().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;
MachineFrameInfo &MFI = MF.getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
unsigned Last = determineLastCalleeSave(CSI);
unsigned StackSlotsUsedByFunclet = 0;
bool SavedBlink = false;
unsigned AlreadyAdjusted = 0;
if (MF.getFunction()->isVarArg()) {
// Add in the varargs area here first.
DEBUG(dbgs() << "Varargs\n");
unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6))
.addReg(ARC::SP)
.addReg(ARC::SP)
.addImm(VarArgsBytes);
}
if (hasFP(MF)) {
DEBUG(dbgs() << "Saving FP\n");
BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9))
.addReg(ARC::SP, RegState::Define)
.addReg(ARC::FP)
.addReg(ARC::SP)
.addImm(-4);
AlreadyAdjusted += 4;
}
if (UseSaveRestoreFunclet && Last > ARC::R14) {
DEBUG(dbgs() << "Creating store funclet.\n");
// BL to __save_r13_to_<TRI->getRegAsmName()>
StackSlotsUsedByFunclet = Last - ARC::R12;
BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6))
.addReg(ARC::SP)
.addReg(ARC::SP)
.addImm(4 * StackSlotsUsedByFunclet);
BuildMI(MBB, MBBI, dl, TII->get(ARC::BL))
.addExternalSymbol(store_funclet_name[Last - ARC::R15])
.addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1);
SavedBlink = true;
}
// If we haven't saved BLINK, but we need to...do that now.
if (MFI.hasCalls() && !SavedBlink) {
DEBUG(dbgs() << "Creating save blink.\n");
BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
AlreadyAdjusted += 4;
}
if (AFI->MaxCallStackReq > 0)
MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq);
// We have already saved some of the stack...
DEBUG(dbgs() << "Adjusting stack by: "
<< (MFI.getStackSize() - AlreadyAdjusted) << "\n");
generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl,
-(MFI.getStackSize() - AlreadyAdjusted), ARC::SP);
if (hasFP(MF)) {
DEBUG(dbgs() << "Setting FP from SP.\n");
BuildMI(MBB, MBBI, dl,
TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6
: ARC::ADD_rrlimm),
ARC::FP)
.addReg(ARC::SP)
.addImm(MFI.getStackSize());
}
// Emit CFI records:
// .cfi_def_cfa_offset StackSize
// .cfi_offset fp, -StackSize
// .cfi_offset blink, -StackSize+4
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize()));
BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
int CurOffset = -4;
if (hasFP(MF)) {
CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset));
BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
CurOffset -= 4;
}
if (MFI.hasCalls()) {
CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset));
BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
}
// CFI for the rest of the registers.
for (const auto &Entry : CSI) {
unsigned Reg = Entry.getReg();
int FI = Entry.getFrameIdx();
// Skip BLINK and FP.
if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK))
continue;
CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
}
}
/// Insert epilog code into the function.
/// For ARC, this inserts a call to a function that restores callee saved
/// registers onto the stack, when enough callee saved registers are required.
void ARCFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
DEBUG(dbgs() << "Emit Epilogue: " << MF.getFunction()->getName() << "\n");
auto *AFI = MF.getInfo<ARCFunctionInfo>();
const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
MachineFrameInfo &MFI = MF.getFrameInfo();
uint64_t StackSize = MF.getFrameInfo().getStackSize();
bool SavedBlink = false;
unsigned AmountAboveFunclet = 0;
// If we have variable sized frame objects, then we have to move
// the stack pointer to a known spot (fp - StackSize).
// Then, replace the frame pointer by (new) [sp,StackSize-4].
// Then, move the stack pointer the rest of the way (sp = sp + StackSize).
if (hasFP(MF)) {
BuildMI(MBB, MBBI, DebugLoc(), TII->get(ARC::SUB_rru6), ARC::SP)
.addReg(ARC::FP)
.addImm(StackSize);
AmountAboveFunclet += 4;
}
// Now, move the stack pointer to the bottom of the save area for the funclet.
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
unsigned Last = determineLastCalleeSave(CSI);
unsigned StackSlotsUsedByFunclet = 0;
// Now, restore the callee save registers.
if (UseSaveRestoreFunclet && Last > ARC::R14) {
// BL to __ld_r13_to_<TRI->getRegAsmName()>
StackSlotsUsedByFunclet = Last - ARC::R12;
AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1);
SavedBlink = true;
}
if (MFI.hasCalls() && !SavedBlink) {
AmountAboveFunclet += 4;
SavedBlink = true;
}
// Move the stack pointer up to the point of the funclet.
if (StackSize - AmountAboveFunclet) {
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6))
.addReg(ARC::SP)
.addReg(ARC::SP)
.addImm(StackSize - AmountAboveFunclet);
}
if (StackSlotsUsedByFunclet) {
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL))
.addExternalSymbol(load_funclet_name[Last - ARC::R15])
.addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6))
.addReg(ARC::SP)
.addReg(ARC::SP)
.addImm(4 * (StackSlotsUsedByFunclet));
}
// Now, pop blink if necessary.
if (SavedBlink) {
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK));
}
// Now, pop fp if necessary.
if (hasFP(MF)) {
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9))
.addReg(ARC::SP, RegState::Define)
.addReg(ARC::FP, RegState::Define)
.addReg(ARC::SP)
.addImm(4);
}
// Relieve the varargs area if necessary.
if (MF.getFunction()->isVarArg()) {
// Add in the varargs area here first.
DEBUG(dbgs() << "Varargs\n");
unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6))
.addReg(ARC::SP)
.addReg(ARC::SP)
.addImm(VarArgsBytes);
}
}
static std::vector<CalleeSavedInfo>::iterator
getSavedReg(std::vector<CalleeSavedInfo> &V, unsigned reg) {
for (auto I = V.begin(), E = V.end(); I != E; ++I) {
if (reg == I->getReg())
return I;
}
return V.end();
}
bool ARCFrameLowering::assignCalleeSavedSpillSlots(
MachineFunction &MF, const TargetRegisterInfo *TRI,
std::vector<CalleeSavedInfo> &CSI) const {
// Use this opportunity to assign the spill slots for all of the potential
// callee save registers (blink, fp, r13->r25) that we care about the
// placement for. We can calculate all of that data here.
int CurOffset = -4;
unsigned Last = determineLastCalleeSave(CSI);
MachineFrameInfo &MFI = MF.getFrameInfo();
if (hasFP(MF)) {
// Create a fixed slot at for FP
int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at "
<< CurOffset << "\n");
(void)StackObj;
CurOffset -= 4;
}
if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) {
// Create a fixed slot for BLINK.
int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for BLINK at "
<< CurOffset << "\n");
(void)StackObj;
CurOffset -= 4;
}
// Create slots for last down to r13.
for (unsigned Which = Last; Which > ARC::R12; Which--) {
auto RegI = getSavedReg(CSI, Which);
if (RegI == CSI.end() || RegI->getFrameIdx() == 0) {
// Always create the stack slot. If for some reason the register isn't in
// the save list, then don't worry about it.
int FI = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
if (RegI != CSI.end())
RegI->setFrameIdx(FI);
} else
MFI.setObjectOffset(RegI->getFrameIdx(), CurOffset);
CurOffset -= 4;
}
for (auto &I : CSI) {
if (I.getReg() > ARC::R12)
continue;
if (I.getFrameIdx() == 0) {
I.setFrameIdx(MFI.CreateFixedSpillStackObject(4, CurOffset, true));
DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx()
<< ") for other register at " << CurOffset << "\n");
} else {
MFI.setObjectOffset(I.getFrameIdx(), CurOffset);
DEBUG(dbgs() << "Updating fixed object (" << I.getFrameIdx()
<< ") for other register at " << CurOffset << "\n");
}
CurOffset -= 4;
}
return true;
}
bool ARCFrameLowering::spillCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const {
DEBUG(dbgs() << "Spill callee saved registers: "
<< MBB.getParent()->getFunction()->getName() << "\n");
// There are routines for saving at least 3 registers (r13 to r15, etc.)
unsigned Last = determineLastCalleeSave(CSI);
if (UseSaveRestoreFunclet && Last > ARC::R14) {
// Use setObjectOffset for these registers.
// Needs to be in or before processFunctionBeforeFrameFinalized.
// Or, do assignCalleeSaveSpillSlots?
// Will be handled in prolog.
return true;
}
return false;
}
bool ARCFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
std::vector<CalleeSavedInfo> &CSI, const TargetRegisterInfo *TRI) const {
DEBUG(dbgs() << "Restore callee saved registers: "
<< MBB.getParent()->getFunction()->getName() << "\n");
// There are routines for saving at least 3 registers (r13 to r15, etc.)
unsigned Last = determineLastCalleeSave(CSI);
if (UseSaveRestoreFunclet && Last > ARC::R14) {
// Will be handled in epilog.
return true;
}
return false;
}
// Adjust local variables that are 4-bytes or larger to 4-byte boundary
void ARCFrameLowering::processFunctionBeforeFrameFinalized(
MachineFunction &MF, RegScavenger *RS) const {
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
DEBUG(dbgs() << "Process function before frame finalized: "
<< MF.getFunction()->getName() << "\n");
MachineFrameInfo &MFI = MF.getFrameInfo();
DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n");
const TargetRegisterClass *RC = &ARC::GPR32RegClass;
if (MFI.hasStackObjects()) {
int RegScavFI = MFI.CreateStackObject(
RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false);
RS->addScavengingFrameIndex(RegScavFI);
DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI << "\n");
}
}
static void emitRegUpdate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator &MBBI, DebugLoc dl,
unsigned Reg, int NumBytes, bool IsAdd,
const ARCInstrInfo *TII) {
unsigned Opc = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6;
BuildMI(MBB, MBBI, dl, TII->get(Opc), Reg)
.addReg(Reg, RegState::Kill)
.addImm(NumBytes);
}
MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr(
MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getFunction()->getName()
<< "\n");
const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
MachineInstr &Old = *I;
DebugLoc dl = Old.getDebugLoc();
unsigned Amt = Old.getOperand(0).getImm();
auto *AFI = MF.getInfo<ARCFunctionInfo>();
if (!hasFP(MF)) {
if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN)
AFI->MaxCallStackReq = Amt;
} else {
if (Amt != 0) {
assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN ||
Old.getOpcode() == ARC::ADJCALLSTACKUP) &&
"Unknown Frame Pseudo.");
bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP);
emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII);
}
}
return MBB.erase(I);
}
bool ARCFrameLowering::hasFP(const MachineFunction &MF) const {
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) ||
MF.getFrameInfo().hasVarSizedObjects() ||
MF.getFrameInfo().isFrameAddressTaken() ||
RegInfo->needsStackRealignment(MF);
return HasFP;
}

View File

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

View File

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

View File

@ -0,0 +1,767 @@
//===- ARCISelLowering.cpp - ARC DAG Lowering 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 implements the ARCTargetLowering class.
//
//===----------------------------------------------------------------------===//
#include "ARCISelLowering.h"
#include "ARC.h"
#include "ARCMachineFunctionInfo.h"
#include "ARCSubtarget.h"
#include "ARCTargetMachine.h"
#include "MCTargetDesc/ARCInfo.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Debug.h"
#include <algorithm>
#define DEBUG_TYPE "arc-lower"
using namespace llvm;
static SDValue lowerCallResult(SDValue Chain, SDValue InFlag,
const SmallVectorImpl<CCValAssign> &RVLocs,
SDLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals);
static ARCCC::CondCode ISDCCtoARCCC(ISD::CondCode isdCC) {
switch (isdCC) {
case ISD::SETUEQ:
return ARCCC::EQ;
case ISD::SETUGT:
return ARCCC::HI;
case ISD::SETUGE:
return ARCCC::HS;
case ISD::SETULT:
return ARCCC::LO;
case ISD::SETULE:
return ARCCC::LS;
case ISD::SETUNE:
return ARCCC::NE;
case ISD::SETEQ:
return ARCCC::EQ;
case ISD::SETGT:
return ARCCC::GT;
case ISD::SETGE:
return ARCCC::GE;
case ISD::SETLT:
return ARCCC::LT;
case ISD::SETLE:
return ARCCC::LE;
case ISD::SETNE:
return ARCCC::NE;
default:
llvm_unreachable("Unhandled ISDCC code.");
}
}
ARCTargetLowering::ARCTargetLowering(const TargetMachine &TM,
const ARCSubtarget &Subtarget)
: TargetLowering(TM), TM(TM), Subtarget(Subtarget) {
// Set up the register classes.
addRegisterClass(MVT::i32, &ARC::GPR32RegClass);
// Compute derived properties from the register classes
computeRegisterProperties(Subtarget.getRegisterInfo());
setStackPointerRegisterToSaveRestore(ARC::SP);
setSchedulingPreference(Sched::Source);
// Use i32 for setcc operations results (slt, sgt, ...).
setBooleanContents(ZeroOrOneBooleanContent);
setBooleanVectorContents(ZeroOrOneBooleanContent);
for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc)
setOperationAction(Opc, MVT::i32, Expand);
// Operations to get us off of the ground.
// Basic.
setOperationAction(ISD::ADD, MVT::i32, Legal);
setOperationAction(ISD::SUB, MVT::i32, Legal);
setOperationAction(ISD::AND, MVT::i32, Legal);
setOperationAction(ISD::SMAX, MVT::i32, Legal);
setOperationAction(ISD::SMIN, MVT::i32, Legal);
// Need barrel shifter.
setOperationAction(ISD::SHL, MVT::i32, Legal);
setOperationAction(ISD::SRA, MVT::i32, Legal);
setOperationAction(ISD::SRL, MVT::i32, Legal);
setOperationAction(ISD::ROTR, MVT::i32, Legal);
setOperationAction(ISD::Constant, MVT::i32, Legal);
setOperationAction(ISD::UNDEF, MVT::i32, Legal);
// Need multiplier
setOperationAction(ISD::MUL, MVT::i32, Legal);
setOperationAction(ISD::MULHS, MVT::i32, Legal);
setOperationAction(ISD::MULHU, MVT::i32, Legal);
setOperationAction(ISD::LOAD, MVT::i32, Legal);
setOperationAction(ISD::STORE, MVT::i32, Legal);
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
setOperationAction(ISD::JumpTable, MVT::i32, Custom);
// Have psuedo instruction for frame addresses.
setOperationAction(ISD::FRAMEADDR, MVT::i32, Legal);
// Custom lower global addresses.
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
// Expand var-args ops.
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
setOperationAction(ISD::VAARG, MVT::Other, Expand);
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
// Other expansions
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
// Sign extend inreg
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Custom);
}
const char *ARCTargetLowering::getTargetNodeName(unsigned Opcode) const {
switch (Opcode) {
case ARCISD::BL:
return "ARCISD::BL";
case ARCISD::CMOV:
return "ARCISD::CMOV";
case ARCISD::CMP:
return "ARCISD::CMP";
case ARCISD::BRcc:
return "ARCISD::BRcc";
case ARCISD::RET:
return "ARCISD::RET";
case ARCISD::GAWRAPPER:
return "ARCISD::GAWRAPPER";
}
return nullptr;
}
//===----------------------------------------------------------------------===//
// Misc Lower Operation implementation
//===----------------------------------------------------------------------===//
SDValue ARCTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
SDValue TVal = Op.getOperand(2);
SDValue FVal = Op.getOperand(3);
SDLoc dl(Op);
ARCCC::CondCode ArcCC = ISDCCtoARCCC(CC);
assert(LHS.getValueType() == MVT::i32 && "Only know how to SELECT_CC i32");
SDValue Cmp = DAG.getNode(ARCISD::CMP, dl, MVT::Glue, LHS, RHS);
return DAG.getNode(ARCISD::CMOV, dl, TVal.getValueType(), TVal, FVal,
DAG.getConstant(ArcCC, dl, MVT::i32), Cmp);
}
SDValue ARCTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
SelectionDAG &DAG) const {
SDValue Op0 = Op.getOperand(0);
SDLoc dl(Op);
assert(Op.getValueType() == MVT::i32 &&
"Unhandled target sign_extend_inreg.");
// These are legal
unsigned Width = cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits();
if (Width == 16 || Width == 8)
return Op;
if (Width >= 32) {
return {};
}
SDValue LS = DAG.getNode(ISD::SHL, dl, MVT::i32, Op0,
DAG.getConstant(32 - Width, dl, MVT::i32));
SDValue SR = DAG.getNode(ISD::SRA, dl, MVT::i32, LS,
DAG.getConstant(32 - Width, dl, MVT::i32));
return SR;
}
SDValue ARCTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
SDValue Chain = Op.getOperand(0);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
SDValue LHS = Op.getOperand(2);
SDValue RHS = Op.getOperand(3);
SDValue Dest = Op.getOperand(4);
SDLoc dl(Op);
ARCCC::CondCode arcCC = ISDCCtoARCCC(CC);
assert(LHS.getValueType() == MVT::i32 && "Only know how to BR_CC i32");
return DAG.getNode(ARCISD::BRcc, dl, MVT::Other, Chain, Dest, LHS, RHS,
DAG.getConstant(arcCC, dl, MVT::i32));
}
SDValue ARCTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const {
auto *N = cast<JumpTableSDNode>(Op);
SDValue GA = DAG.getTargetJumpTable(N->getIndex(), MVT::i32);
return DAG.getNode(ARCISD::GAWRAPPER, SDLoc(N), MVT::i32, GA);
}
#include "ARCGenCallingConv.inc"
//===----------------------------------------------------------------------===//
// Call Calling Convention Implementation
//===----------------------------------------------------------------------===//
/// ARC call implementation
SDValue ARCTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const {
SelectionDAG &DAG = CLI.DAG;
SDLoc &dl = CLI.DL;
SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
SDValue Chain = CLI.Chain;
SDValue Callee = CLI.Callee;
CallingConv::ID CallConv = CLI.CallConv;
bool IsVarArg = CLI.IsVarArg;
bool &IsTailCall = CLI.IsTailCall;
IsTailCall = false; // Do not support tail calls yet.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext());
CCInfo.AnalyzeCallOperands(Outs, CC_ARC);
SmallVector<CCValAssign, 16> RVLocs;
// Analyze return values to determine the number of bytes of stack required.
CCState RetCCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
*DAG.getContext());
RetCCInfo.AllocateStack(CCInfo.getNextStackOffset(), 4);
RetCCInfo.AnalyzeCallResult(Ins, RetCC_ARC);
// Get a count of how many bytes are to be pushed on the stack.
unsigned NumBytes = RetCCInfo.getNextStackOffset();
auto PtrVT = getPointerTy(DAG.getDataLayout());
Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl);
SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass;
SmallVector<SDValue, 12> MemOpChains;
SDValue StackPtr;
// Walk the register/memloc assignments, inserting copies/loads.
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
SDValue Arg = OutVals[i];
// Promote the value if needed.
switch (VA.getLocInfo()) {
default:
llvm_unreachable("Unknown loc info!");
case CCValAssign::Full:
break;
case CCValAssign::SExt:
Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
break;
case CCValAssign::ZExt:
Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
break;
case CCValAssign::AExt:
Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg);
break;
}
// Arguments that can be passed on register must be kept at
// RegsToPass vector
if (VA.isRegLoc()) {
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
} else {
assert(VA.isMemLoc() && "Must be register or memory argument.");
if (!StackPtr.getNode())
StackPtr = DAG.getCopyFromReg(Chain, dl, ARC::SP,
getPointerTy(DAG.getDataLayout()));
// Calculate the stack position.
SDValue SOffset = DAG.getIntPtrConstant(VA.getLocMemOffset(), dl);
SDValue PtrOff = DAG.getNode(
ISD::ADD, dl, getPointerTy(DAG.getDataLayout()), StackPtr, SOffset);
SDValue Store =
DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo());
MemOpChains.push_back(Store);
IsTailCall = false;
}
}
// Transform all store nodes into one single node because
// all store nodes are independent of each other.
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
// Build a sequence of copy-to-reg nodes chained together with token
// chain and flag operands which copy the outgoing args into registers.
// The InFlag in necessary since all emitted instructions must be
// stuck together.
SDValue Glue;
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
RegsToPass[i].second, Glue);
Glue = Chain.getValue(1);
}
// If the callee is a GlobalAddress node (quite common, every direct call is)
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
// Likewise ExternalSymbol -> TargetExternalSymbol.
bool IsDirect = true;
if (auto *G = dyn_cast<GlobalAddressSDNode>(Callee))
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32);
else if (auto *E = dyn_cast<ExternalSymbolSDNode>(Callee))
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);
else
IsDirect = false;
// Branch + Link = #chain, #target_address, #opt_in_flags...
// = Chain, Callee, Reg#1, Reg#2, ...
//
// Returns a chain & a flag for retval copy to use.
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
SmallVector<SDValue, 8> Ops;
Ops.push_back(Chain);
Ops.push_back(Callee);
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
RegsToPass[i].second.getValueType()));
// Add a register mask operand representing the call-preserved registers.
const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
const uint32_t *Mask =
TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv);
assert(Mask && "Missing call preserved mask for calling convention");
Ops.push_back(DAG.getRegisterMask(Mask));
if (Glue.getNode())
Ops.push_back(Glue);
Chain = DAG.getNode(IsDirect ? ARCISD::BL : ARCISD::JL, dl, NodeTys, Ops);
Glue = Chain.getValue(1);
// Create the CALLSEQ_END node.
Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, dl, PtrVT, true),
DAG.getConstant(0, dl, PtrVT, true), Glue, dl);
Glue = Chain.getValue(1);
// Handle result values, copying them out of physregs into vregs that we
// return.
if (IsTailCall)
return Chain;
return lowerCallResult(Chain, Glue, RVLocs, dl, DAG, InVals);
}
/// Lower the result values of a call into the appropriate copies out of
/// physical registers / memory locations.
static SDValue lowerCallResult(SDValue Chain, SDValue Glue,
const SmallVectorImpl<CCValAssign> &RVLocs,
SDLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) {
SmallVector<std::pair<int, unsigned>, 4> ResultMemLocs;
// Copy results out of physical registers.
for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
const CCValAssign &VA = RVLocs[i];
if (VA.isRegLoc()) {
SDValue RetValue;
RetValue =
DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), VA.getValVT(), Glue);
Chain = RetValue.getValue(1);
Glue = RetValue.getValue(2);
InVals.push_back(RetValue);
} else {
assert(VA.isMemLoc() && "Must be memory location.");
ResultMemLocs.push_back(
std::make_pair(VA.getLocMemOffset(), InVals.size()));
// Reserve space for this result.
InVals.push_back(SDValue());
}
}
// Copy results out of memory.
SmallVector<SDValue, 4> MemOpChains;
for (unsigned i = 0, e = ResultMemLocs.size(); i != e; ++i) {
int Offset = ResultMemLocs[i].first;
unsigned Index = ResultMemLocs[i].second;
SDValue StackPtr = DAG.getRegister(ARC::SP, MVT::i32);
SDValue SpLoc = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr,
DAG.getConstant(Offset, dl, MVT::i32));
SDValue Load =
DAG.getLoad(MVT::i32, dl, Chain, SpLoc, MachinePointerInfo());
InVals[Index] = Load;
MemOpChains.push_back(Load.getValue(1));
}
// Transform all loads nodes into one single node because
// all load nodes are independent of each other.
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
return Chain;
}
//===----------------------------------------------------------------------===//
// Formal Arguments Calling Convention Implementation
//===----------------------------------------------------------------------===//
namespace {
struct ArgDataPair {
SDValue SDV;
ISD::ArgFlagsTy Flags;
};
} // end anonymous namespace
/// ARC formal arguments implementation
SDValue ARCTargetLowering::LowerFormalArguments(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
switch (CallConv) {
default:
llvm_unreachable("Unsupported calling convention");
case CallingConv::C:
case CallingConv::Fast:
return LowerCallArguments(Chain, CallConv, IsVarArg, Ins, dl, DAG, InVals);
}
}
/// Transform physical registers into virtual registers, and generate load
/// operations for argument places on the stack.
SDValue ARCTargetLowering::LowerCallArguments(
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo &MFI = MF.getFrameInfo();
MachineRegisterInfo &RegInfo = MF.getRegInfo();
auto *AFI = MF.getInfo<ARCFunctionInfo>();
// Assign locations to all of the incoming arguments.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
*DAG.getContext());
CCInfo.AnalyzeFormalArguments(Ins, CC_ARC);
unsigned StackSlotSize = 4;
if (!IsVarArg)
AFI->setReturnStackOffset(CCInfo.getNextStackOffset());
// All getCopyFromReg ops must precede any getMemcpys to prevent the
// scheduler clobbering a register before it has been copied.
// The stages are:
// 1. CopyFromReg (and load) arg & vararg registers.
// 2. Chain CopyFromReg nodes into a TokenFactor.
// 3. Memcpy 'byVal' args & push final InVals.
// 4. Chain mem ops nodes into a TokenFactor.
SmallVector<SDValue, 4> CFRegNode;
SmallVector<ArgDataPair, 4> ArgData;
SmallVector<SDValue, 4> MemOps;
// 1a. CopyFromReg (and load) arg registers.
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
SDValue ArgIn;
if (VA.isRegLoc()) {
// Arguments passed in registers
EVT RegVT = VA.getLocVT();
switch (RegVT.getSimpleVT().SimpleTy) {
default: {
DEBUG(errs() << "LowerFormalArguments Unhandled argument type: "
<< RegVT.getSimpleVT().SimpleTy << "\n");
llvm_unreachable("Unhandled LowerFormalArguments type.");
}
case MVT::i32:
unsigned VReg = RegInfo.createVirtualRegister(&ARC::GPR32RegClass);
RegInfo.addLiveIn(VA.getLocReg(), VReg);
ArgIn = DAG.getCopyFromReg(Chain, dl, VReg, RegVT);
CFRegNode.push_back(ArgIn.getValue(ArgIn->getNumValues() - 1));
}
} else {
// sanity check
assert(VA.isMemLoc());
// Load the argument to a virtual register
unsigned ObjSize = VA.getLocVT().getStoreSize();
assert((ObjSize <= StackSlotSize) && "Unhandled argument");
// Create the frame index object for this incoming parameter...
int FI = MFI.CreateFixedObject(ObjSize, VA.getLocMemOffset(), true);
// Create the SelectionDAG nodes corresponding to a load
// from this parameter
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
ArgIn = DAG.getLoad(VA.getLocVT(), dl, Chain, FIN,
MachinePointerInfo::getFixedStack(MF, FI));
}
const ArgDataPair ADP = {ArgIn, Ins[i].Flags};
ArgData.push_back(ADP);
}
// 1b. CopyFromReg vararg registers.
if (IsVarArg) {
// Argument registers
static const MCPhysReg ArgRegs[] = {ARC::R0, ARC::R1, ARC::R2, ARC::R3,
ARC::R4, ARC::R5, ARC::R6, ARC::R7};
auto *AFI = MF.getInfo<ARCFunctionInfo>();
unsigned FirstVAReg = CCInfo.getFirstUnallocated(ArgRegs);
if (FirstVAReg < array_lengthof(ArgRegs)) {
int Offset = 0;
// Save remaining registers, storing higher register numbers at a higher
// address
// There are (array_lengthof(ArgRegs) - FirstVAReg) registers which
// need to be saved.
int VarFI =
MFI.CreateFixedObject((array_lengthof(ArgRegs) - FirstVAReg) * 4,
CCInfo.getNextStackOffset(), true);
AFI->setVarArgsFrameIndex(VarFI);
SDValue FIN = DAG.getFrameIndex(VarFI, MVT::i32);
for (unsigned i = FirstVAReg; i < array_lengthof(ArgRegs); i++) {
// Move argument from phys reg -> virt reg
unsigned VReg = RegInfo.createVirtualRegister(&ARC::GPR32RegClass);
RegInfo.addLiveIn(ArgRegs[i], VReg);
SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32);
CFRegNode.push_back(Val.getValue(Val->getNumValues() - 1));
SDValue VAObj = DAG.getNode(ISD::ADD, dl, MVT::i32, FIN,
DAG.getConstant(Offset, dl, MVT::i32));
// Move argument from virt reg -> stack
SDValue Store =
DAG.getStore(Val.getValue(1), dl, Val, VAObj, MachinePointerInfo());
MemOps.push_back(Store);
Offset += 4;
}
} else {
llvm_unreachable("Too many var args parameters.");
}
}
// 2. Chain CopyFromReg nodes into a TokenFactor.
if (!CFRegNode.empty())
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, CFRegNode);
// 3. Memcpy 'byVal' args & push final InVals.
// Aggregates passed "byVal" need to be copied by the callee.
// The callee will use a pointer to this copy, rather than the original
// pointer.
for (const auto &ArgDI : ArgData) {
if (ArgDI.Flags.isByVal() && ArgDI.Flags.getByValSize()) {
unsigned Size = ArgDI.Flags.getByValSize();
unsigned Align = std::max(StackSlotSize, ArgDI.Flags.getByValAlign());
// Create a new object on the stack and copy the pointee into it.
int FI = MFI.CreateStackObject(Size, Align, false);
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
InVals.push_back(FIN);
MemOps.push_back(DAG.getMemcpy(
Chain, dl, FIN, ArgDI.SDV, DAG.getConstant(Size, dl, MVT::i32), Align,
false, false, false, MachinePointerInfo(), MachinePointerInfo()));
} else {
InVals.push_back(ArgDI.SDV);
}
}
// 4. Chain mem ops nodes into a TokenFactor.
if (!MemOps.empty()) {
MemOps.push_back(Chain);
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps);
}
return Chain;
}
//===----------------------------------------------------------------------===//
// Return Value Calling Convention Implementation
//===----------------------------------------------------------------------===//
bool ARCTargetLowering::CanLowerReturn(
CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
if (!CCInfo.CheckReturn(Outs, RetCC_ARC))
return false;
if (CCInfo.getNextStackOffset() != 0 && IsVarArg)
return false;
return true;
}
SDValue
ARCTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
const SDLoc &dl, SelectionDAG &DAG) const {
auto *AFI = DAG.getMachineFunction().getInfo<ARCFunctionInfo>();
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
// CCValAssign - represent the assignment of
// the return value to a location
SmallVector<CCValAssign, 16> RVLocs;
// CCState - Info about the registers and stack slot.
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
*DAG.getContext());
// Analyze return values.
if (!IsVarArg)
CCInfo.AllocateStack(AFI->getReturnStackOffset(), 4);
CCInfo.AnalyzeReturn(Outs, RetCC_ARC);
SDValue Flag;
SmallVector<SDValue, 4> RetOps(1, Chain);
SmallVector<SDValue, 4> MemOpChains;
// Handle return values that must be copied to memory.
for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
CCValAssign &VA = RVLocs[i];
if (VA.isRegLoc())
continue;
assert(VA.isMemLoc());
if (IsVarArg) {
report_fatal_error("Can't return value from vararg function in memory");
}
int Offset = VA.getLocMemOffset();
unsigned ObjSize = VA.getLocVT().getStoreSize();
// Create the frame index object for the memory location.
int FI = MFI.CreateFixedObject(ObjSize, Offset, false);
// Create a SelectionDAG node corresponding to a store
// to this memory location.
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
MemOpChains.push_back(DAG.getStore(
Chain, dl, OutVals[i], FIN,
MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI)));
}
// Transform all store nodes into one single node because
// all stores are independent of each other.
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
// Now handle return values copied to registers.
for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
CCValAssign &VA = RVLocs[i];
if (!VA.isRegLoc())
continue;
// Copy the result values into the output registers.
Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Flag);
// guarantee that all emitted copies are
// stuck together, avoiding something bad
Flag = Chain.getValue(1);
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
}
RetOps[0] = Chain; // Update chain.
// Add the flag if we have it.
if (Flag.getNode())
RetOps.push_back(Flag);
// What to do with the RetOps?
return DAG.getNode(ARCISD::RET, dl, MVT::Other, RetOps);
}
//===----------------------------------------------------------------------===//
// Target Optimization Hooks
//===----------------------------------------------------------------------===//
SDValue ARCTargetLowering::PerformDAGCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
return {};
}
//===----------------------------------------------------------------------===//
// Addressing mode description hooks
//===----------------------------------------------------------------------===//
/// Return true if the addressing mode represented by AM is legal for this
/// target, for a load/store of the specified type.
bool ARCTargetLowering::isLegalAddressingMode(const DataLayout &DL,
const AddrMode &AM, Type *Ty,
unsigned AS,
Instruction *I) const {
return AM.Scale == 0;
}
// Don't emit tail calls for the time being.
bool ARCTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
return false;
}
SDValue ARCTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
const ARCRegisterInfo &ARI = *Subtarget.getRegisterInfo();
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo &MFI = MF.getFrameInfo();
MFI.setFrameAddressIsTaken(true);
EVT VT = Op.getValueType();
SDLoc dl(Op);
assert(cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() == 0 &&
"Only support lowering frame addr of current frame.");
unsigned FrameReg = ARI.getFrameRegister(MF);
return DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
}
SDValue ARCTargetLowering::LowerGlobalAddress(SDValue Op,
SelectionDAG &DAG) const {
const GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Op);
const GlobalValue *GV = GN->getGlobal();
SDLoc dl(GN);
int64_t Offset = GN->getOffset();
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, Offset);
return DAG.getNode(ARCISD::GAWRAPPER, dl, MVT::i32, GA);
}
static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) {
MachineFunction &MF = DAG.getMachineFunction();
auto *FuncInfo = MF.getInfo<ARCFunctionInfo>();
// vastart just stores the address of the VarArgsFrameIndex slot into the
// memory location argument.
SDLoc dl(Op);
EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
SDValue FR = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT);
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
return DAG.getStore(Op.getOperand(0), dl, FR, Op.getOperand(1),
MachinePointerInfo(SV));
}
SDValue ARCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
case ISD::GlobalAddress:
return LowerGlobalAddress(Op, DAG);
case ISD::FRAMEADDR:
return LowerFRAMEADDR(Op, DAG);
case ISD::SELECT_CC:
return LowerSELECT_CC(Op, DAG);
case ISD::BR_CC:
return LowerBR_CC(Op, DAG);
case ISD::SIGN_EXTEND_INREG:
return LowerSIGN_EXTEND_INREG(Op, DAG);
case ISD::JumpTable:
return LowerJumpTable(Op, DAG);
case ISD::VASTART:
return LowerVASTART(Op, DAG);
default:
llvm_unreachable("unimplemented operand");
}
}

View File

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

View File

@ -0,0 +1,508 @@
//===- ARCInstrFormats.td - ARC Instruction Formats --------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Instruction format superclass
//===----------------------------------------------------------------------===//
class Encoding64 {
field bits<64> Inst;
field bits<64> SoftFail = 0;
}
// Address operands
def immU6 : Operand<i32>, PatLeaf<(imm), [{
return isUInt<6>(N->getSExtValue()); }]> {
}
def immS12 : Operand<i32>, PatLeaf<(imm), [{
return isInt<12>(N->getSExtValue()); }]> {
let DecoderMethod = "DecodeS12Operand";
}
def immS9 : Operand<i32>, PatLeaf<(imm), [{
return isInt<9>(N->getSExtValue()); }]> {
let DecoderMethod = "DecodeS9Operand";
}
def MEMii : Operand<i32> {
let MIOperandInfo = (ops i32imm, i32imm);
}
def MEMrs9 : Operand<iAny> {
let MIOperandInfo = (ops GPR32:$B, immS9:$S9);
let PrintMethod = "printMemOperandRI";
let DecoderMethod = "DecodeMEMrs9";
}
def MEMrlimm : Operand<iAny> {
let MIOperandInfo = (ops GPR32:$B, i32imm:$LImm);
let PrintMethod = "printMemOperandRI";
let DecoderMethod = "DecodeMEMrlimm";
}
class InstARC<int sz, dag outs, dag ins, string asmstr, list<dag> pattern>
: Instruction, Encoding64 {
let Namespace = "ARC";
dag OutOperandList = outs;
dag InOperandList = ins;
let AsmString = asmstr;
let Pattern = pattern;
let Size = sz;
}
// ARC pseudo instructions format
class PseudoInstARC<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstARC<0, outs, ins, asmstr, pattern> {
let isPseudo = 1;
}
//===----------------------------------------------------------------------===//
// Instruction formats
//===----------------------------------------------------------------------===//
// All 32-bit ARC instructions have a 5-bit "major" opcode class designator
// in bits 27-31.
//
// Some general naming conventions:
// N - Delay Slot bit. ARC v2 branch instructions have an optional delay slot
// which is encoded with this bit. When set, a delay slot exists.
// cc - Condition code.
// SX - Signed X-bit immediate.
// UX - Unsigned X-bit immediate.
//
// [ABC] - 32-bit register operand. These are 6-bit fields. This encodes the
// standard 32 general purpose registers, and allows use of additional
// (extension) registers. This also encodes an instruction that uses
// a 32-bit Long Immediate (LImm), using 0x3e==62 as the field value.
// This makes 32-bit format instructions with Long Immediates
// 64-bit instructions, with the Long Immediate in bits 32-63.
// A - Inst[5-0] = A[5-0], when the format has A. A is always a register.
// B - Inst[14-12] = B[5-3], Inst[26-24] = B[2-0], when the format has B.
// B is always a register.
// C - Inst[11-6] = C[5-0], when the format has C. C can either be a register,
// or a 6-bit unsigned immediate (immU6), depending on the format.
// F - Many instructions specify a flag bit. When set, the result of these
// instructions will set the ZNCV flags of the STATUS32 register
// (Zero/Negative/Carry/oVerflow).
// Branch Instructions.
class F32_BR<bits<5> major, dag outs, dag ins, bit b16, string asmstr,
list<dag> pattern> :
InstARC<4, outs, ins, asmstr, pattern> {
bit N;
let Inst{31-27} = major;
let Inst{16} = b16;
let Inst{5} = N;
}
class F32_BR_COND<bits<5> major, dag outs, dag ins, bit b16, string asmstr,
list<dag> pattern> :
F32_BR<major, outs, ins, b16, asmstr, pattern> {
bits<21> S21; // 2-byte aligned 21-bit byte-offset.
bits<5> cc;
let Inst{26-18} = S21{10-2};
let Inst{15-6} = S21{20-11};
let Inst{4-0} = cc;
}
class F32_BR_UCOND_FAR<bits<5> major, dag outs, dag ins, bit b16, string asmstr,
list<dag> pattern> :
F32_BR<major, outs, ins, b16, asmstr, pattern> {
bits<25> S25; // 2-byte aligned 25-bit byte-offset.
let Inst{26-18} = S25{10-2};
let Inst{15-6} = S25{20-11};
let Inst{4} = 0;
let Inst{3-0} = S25{24-21};
}
class F32_BR0_COND<dag outs, dag ins, string asmstr, list<dag> pat> :
F32_BR_COND<0b00000, outs, ins, 0, asmstr, pat> {
let Inst{17} = S21{1};
}
// Branch targets are 2-byte aligned, so S25[0] is implied 0.
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0 |
// |S25[10-1] | 1|S25[20-11] |N|0|S25[24-21]|
class F32_BR0_UCOND_FAR<dag outs, dag ins, string asmstr, list<dag> pat> :
F32_BR_UCOND_FAR<0b00000, outs, ins, 1, asmstr, pat> {
let Inst{17} = S25{1};
}
// BL targets (functions) are 4-byte aligned, so S25[1-0] = 0b00
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0 |
// |S25[10-2] | 1| 0|S25[20-11] |N|0|S25[24-21]|
class F32_BR1_BL_UCOND_FAR<dag outs, dag ins, string asmstr, list<dag> pat> :
F32_BR_UCOND_FAR<0b00001, outs, ins, 0, asmstr, pat> {
let Inst{17} = 1;
}
// BLcc targets have 21 bit range, and are 4-byte aligned.
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
// |S25[10-2] | 0| 0|S25[20-11] |N|0|cc |
class F32_BR1_BL_COND<dag outs, dag ins, string asmstr, list<dag> pat> :
F32_BR_COND<0b00001, outs, ins, 0, asmstr, pat> {
let Inst{17} = 0;
}
// BRcc targets have limited 9-bit range. These are for compare and branch
// in single instruction. Their targets are 2-byte aligned. They also use
// a different (3-bit) set of condition codes.
// |26|25|24|23|22|21|20|19|18|17|16|15 |14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
// |B[2-0] |S9[7-1] | 1|S9[8]|B[5-3] |C |N|u|0|cc |
class F32_BR1_BCC<dag outs, dag ins, string asmstr, bit IsU6,
list<dag> pattern> :
InstARC<4, outs, ins, asmstr, pattern> {
bits<3> cc;
bits<6> B;
bits<6> C;
bit N;
bits<9> S9; // 2-byte aligned 9-bit byte-offset.
let Inst{31-27} = 0b00001;
let Inst{26-24} = B{2-0};
let Inst{23-17} = S9{7-1};
let Inst{16} = 1;
let Inst{15} = S9{8};
let Inst{14-12} = B{5-3};
let Inst{11-6} = C;
let Inst{5} = N;
let Inst{4} = IsU6;
let Inst{3} = 0;
let Inst{2-0} = cc;
}
// General operations instructions.
// Single Operand Instructions. Inst[5-0] specifies the specific operation
// for this format.
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
// |B[2-0] | 0| 0| 1| 0| 1| 1| 1| 1| F|B[5-3] |C |subop |
class F32_SOP_RR<bits<5> major, bits<6> subop, bit F, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<4, outs, ins, asmstr, pattern> {
bits<6> C;
bits<6> B;
let Inst{31-27} = major;
let Inst{26-24} = B{2-0};
let Inst{23-22} = 0b00;
let Inst{21-16} = 0b101111;
let Inst{15} = F;
let Inst{14-12} = B{5-3};
let Inst{11-6} = C;
let Inst{5-0} = subop;
}
// Dual Operand Instructions. Inst[21-16] specifies the specific operation
// for this format.
// 3-register Dual Operand instruction.
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
// |B[2-0] | 0| 0| subop| F|B[5-3] |C |A |
class F32_DOP_RR<bits<5> major, bits<6> subop, bit F, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<4, outs, ins, asmstr, pattern> {
bits<6> C;
bits<6> B;
bits<6> A;
let Inst{31-27} = major;
let Inst{26-24} = B{2-0};
let Inst{23-22} = 0b00;
let Inst{21-16} = subop;
let Inst{15} = F;
let Inst{14-12} = B{5-3};
let Inst{11-6} = C;
let Inst{5-0} = A;
}
// Conditional Dual Operand instruction. This instruction uses B as the
// first 2 operands (i.e, add.cc B, B, C).
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
// |B[2-0] | 1| 1| subop| F|B[5-3] |C |A |
class F32_DOP_CC_RR<bits<5> major, bits<6> subop, bit F, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<4, outs, ins, asmstr, pattern> {
bits<5> cc;
bits<6> C;
bits<6> B;
let Inst{31-27} = major;
let Inst{26-24} = B{2-0};
let Inst{23-22} = 0b11;
let Inst{21-16} = subop;
let Inst{15} = F;
let Inst{14-12} = B{5-3};
let Inst{11-6} = C;
let Inst{5} = 0;
let Inst{4-0} = cc;
}
// 2-register, unsigned 6-bit immediate Dual Operand instruction.
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
// |B[2-0] | 0| 1| subop| F|B[5-3] |U6 |A |
class F32_DOP_RU6<bits<5> major, bits<6> subop, bit F, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<4, outs, ins, asmstr, pattern> {
bits<6> U6;
bits<6> B;
bits<6> A;
let Inst{31-27} = major;
let Inst{26-24} = B{2-0};
let Inst{23-22} = 0b01;
let Inst{21-16} = subop;
let Inst{15} = F;
let Inst{14-12} = B{5-3};
let Inst{11-6} = U6;
let Inst{5-0} = A;
}
// 2-register, signed 12-bit immediate Dual Operand instruction.
// This instruction uses B as the first 2 operands (i.e., add B, B, -128).
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
// |B[2-0] | 1| 0| subop| F|B[5-3] |S12[5-0] |S12[11-6] |
class F32_DOP_RS12<bits<5> major, bits<6> subop, bit F, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<4, outs, ins, asmstr, pattern> {
bits<6> B;
bits<12> S12;
let Inst{31-27} = major;
let Inst{26-24} = B{2-0};
let Inst{23-22} = 0b10;
let Inst{21-16} = subop;
let Inst{15} = F;
let Inst{14-12} = B{5-3};
let Inst{11-6} = S12{5-0};
let Inst{5-0} = S12{11-6};
}
// 2-register, 32-bit immediate (LImm) Dual Operand instruction.
// This instruction has the 32-bit immediate in bits 32-63, and
// 62 in the C register operand slot, but is otherwise F32_DOP_RR.
class F32_DOP_RLIMM<bits<5> major, bits<6> subop, bit F, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<8, outs, ins, asmstr, pattern> {
bits<6> B;
bits<6> A;
bits<32> LImm;
let Inst{63-32} = LImm;
let Inst{31-27} = major;
let Inst{26-24} = B{2-0};
let Inst{23-22} = 0b00;
let Inst{21-16} = subop;
let Inst{15} = F;
let Inst{14-12} = B{5-3};
let Inst{11-6} = 0b111110;
let Inst{5-0} = A;
}
// Load and store instructions.
// In addition to the previous naming conventions, load and store instructions
// have:
// di - Uncached bit. When set, loads/stores bypass the cache and access
// memory directly.
// aa - Incrementing mode. Loads and stores can write-back address pre- or
// post- memory operation.
// zz - Memory size (can be 8/16/32 bit load/store).
// x - Sign-extending. When set, short loads can be sign-extended to 32-bits.
// Loads and Stores support different memory addressing modes:
// Base Register + Signed 9-bit Immediate: Both Load/Store.
// LImm: Both Load/Store (Load/Store from a fixed 32-bit address).
// Register + Register: Load Only.
// Register + LImm: Load Only.
// Register + S9 Load. (B + S9)
// |26|25|24|23|22|21|20|19|18|17|16|15 |14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
// |B[2-0] |S9[7-0] |S9[8]|B[5-3] |di|aa |zz |x|A |
class F32_LD_RS9<bit x, bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<4, outs, ins, asmstr, pattern> {
bits<6> B;
bits<6> A;
bits<9> S9;
let Inst{31-27} = 0b00010;
let Inst{26-24} = B{2-0};
let Inst{23-16} = S9{7-0};
let Inst{15} = S9{8};
let Inst{14-12} = B{5-3};
let Inst{11} = di;
let Inst{10-9} = aa;
let Inst{8-7} = zz;
let Inst{6} = x;
let Inst{5-0} = A;
}
class F32_LD_ADDR<bit x, bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
string asmstr, list<dag> pattern> :
F32_LD_RS9<x, aa, di, zz, outs, ins, asmstr, pattern> {
bits<15> addr;
let B = addr{14-9};
let S9 = addr{8-0};
}
// LImm Load. The 32-bit immediate address is in Inst[63-32].
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
// | 1| 1| 0| 0 | 1| 1| 1|di| 0|0|zz |x|A |
class F32_LD_LIMM<bit x, bit di, bits<2> zz, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<8, outs, ins, asmstr, pattern> {
bits<6> LImmReg = 0b111110;
bits<6> A;
bits<32> LImm;
let Inst{63-32} = LImm;
let Inst{31-27} = 0b00010;
let Inst{26-24} = LImmReg{2-0};
let Inst{23-15} = 0;
let Inst{14-12} = LImmReg{5-3};
let Inst{11} = di;
let Inst{10-9} = 0;
let Inst{8-7} = zz;
let Inst{6} = x;
let Inst{5-0} = A;
let DecoderMethod = "DecodeLdLImmInstruction";
}
// Register + LImm load. The 32-bit immediate address is in Inst[63-32].
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
// |B[2-0] |aa | 1| 1| 0|zz | x|di|B[5-3] | 1| 1|1|1|1|0|A |
class F32_LD_RLIMM<bit x, bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<8, outs, ins, asmstr, pattern> {
bits<6> LImmReg = 0b111110;
bits<32> LImm;
bits<6> B;
bits<6> A;
bits<38> addr;
let B = addr{37-32};
let LImm = addr{31-0};
let Inst{63-32} = LImm;
let Inst{31-27} = 0b00100;
let Inst{26-24} = B{2-0};
let Inst{23-22} = aa;
let Inst{21-19} = 0b110;
let Inst{18-17} = zz;
let Inst{16} = x;
let Inst{15} = di;
let Inst{14-12} = B{5-3};
let Inst{11-6} = LImmReg;
let Inst{5-0} = A;
let DecoderMethod = "DecodeLdRLImmInstruction";
}
// Register + S9 Store. (B + S9)
// |26|25|24|23|22|21|20|19|18|17|16|15 |14|13|12|11|10|9|8|7|6|5 |4|3|2|1|0|
// |B[2-0] |S9[7-0] |S9[8]|B[5-3] |C |di|aa |zz |0|
class F32_ST_RS9<bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<4, outs, ins, asmstr, pattern> {
bits<6> B;
bits<6> C;
bits<9> S9;
let Inst{31-27} = 0b00011;
let Inst{26-24} = B{2-0};
let Inst{23-16} = S9{7-0};
let Inst{15} = S9{8};
let Inst{14-12} = B{5-3};
let Inst{11-6} = C;
let Inst{5} = di;
let Inst{4-3} = aa;
let Inst{2-1} = zz;
let Inst{0} = 0;
}
class F32_ST_ADDR<bits<2> aa, bit di, bits<2> zz, dag outs, dag ins,
string asmstr, list<dag> pattern> :
F32_ST_RS9<aa, di, zz, outs, ins, asmstr, pattern> {
bits<15> addr;
let B = addr{14-9};
let S9 = addr{8-0};
}
// LImm Store.
// |26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|9|8|7|6|5 |4|3|2|1|0|
// | 1| 1| 0| 0 | 1| 1| 1|C |di|0|0|zz |0|
class F32_ST_LIMM<bit di, bits<2> zz, dag outs, dag ins,
string asmstr, list<dag> pattern> :
InstARC<8, outs, ins, asmstr, pattern> {
bits<6> LImmReg = 0b111110;
bits<6> C;
bits<32> LImm;
let Inst{63-32} = LImm;
let Inst{31-27} = 0b00011;
let Inst{26-24} = LImmReg{2-0};
let Inst{23-15} = 0;
let Inst{14-12} = LImmReg{5-3};
let Inst{11-6} = C;
let Inst{5} = di;
let Inst{4-3} = 0;
let Inst{2-1} = zz;
let Inst{0} = 0;
let DecoderMethod = "DecodeStLImmInstruction";
}
// Special types for different instruction operands.
def cmovpred : Operand<i32>, PredicateOp,
ComplexPattern<i32, 2, "SelectCMOVPred"> {
let MIOperandInfo = (ops i32imm, i32imm);
let PrintMethod = "printPredicateOperand";
}
def ccond : Operand<i32> {
let MIOperandInfo = (ops i32imm);
let PrintMethod = "printPredicateOperand";
}
def brccond : Operand<i32> {
let MIOperandInfo = (ops i32imm);
let PrintMethod = "printBRCCPredicateOperand";
}
// Branch targets of different offset sizes.
def btarget : Operand<OtherVT> {
let OperandType = "OPERAND_PCREL";
}
def btargetS9 : Operand<OtherVT> {
let OperandType = "OPERAND_PCREL";
let DecoderMethod = "DecodeBranchTargetS9";
}
def btargetS21 : Operand<OtherVT> {
let OperandType = "OPERAND_PCREL";
let DecoderMethod = "DecodeBranchTargetS21";
}
def btargetS25 : Operand<OtherVT> {
let OperandType = "OPERAND_PCREL";
let DecoderMethod = "DecodeBranchTargetS25";
}
def calltargetS25: Operand<i32> {
let OperandType = "OPERAND_PCREL";
let DecoderMethod = "DecodeBranchTargetS25";
}

View File

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

View File

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

View File

@ -0,0 +1,504 @@
//===- ARCInstrInfo.td - Target Description 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 file describes the ARC instructions in TableGen format.
//
//===----------------------------------------------------------------------===//
include "ARCInstrFormats.td"
// ---------------------------------------------------------------------------
// Selection DAG Nodes.
// ---------------------------------------------------------------------------
// Selection DAG types.
def SDT_ARCcmptst : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>;
def SDT_ARCcmov : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>]>;
def SDT_ARCmov : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>]>;
def SDT_ARCbrcc : SDTypeProfile<0, 4, []>;
def SDT_ARCBranchLink : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
def SDT_ARCCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32>,
SDTCisVT<1, i32> ]>;
def SDT_ARCCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
SDTCisVT<1, i32> ]>;
// Global Address.
def ARCGAWrapper : SDNode<"ARCISD::GAWRAPPER", SDT_ARCmov, []>;
// Comparison
def ARCcmp : SDNode<"ARCISD::CMP", SDT_ARCcmptst, [SDNPOutGlue]>;
// Conditionanal mov
def ARCcmov : SDNode<"ARCISD::CMOV", SDT_ARCcmov, [SDNPInGlue]>;
// Conditional Branch
def ARCbrcc : SDNode<"ARCISD::BRcc", SDT_ARCbrcc,
[SDNPHasChain, SDNPInGlue, SDNPOutGlue]>;
// Direct Call
def ARCBranchLink : SDNode<"ARCISD::BL",SDT_ARCBranchLink,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
SDNPVariadic]>;
// Indirect Call
def ARCJumpLink : SDNode<"ARCISD::JL",SDT_ARCBranchLink,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
SDNPVariadic]>;
// Call return
def ret : SDNode<"ARCISD::RET", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
// Call sequencing nodes.
// These are target-independent nodes, but have target-specific formats.
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_ARCCallSeqStart,
[SDNPHasChain, SDNPOutGlue]>;
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_ARCCallSeqEnd,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
//===----------------------------------------------------------------------===//
// Instruction Pattern Stuff
//===----------------------------------------------------------------------===//
def imm32 : ImmLeaf<i32, [{
return (Imm & 0xFFFFFFFF) == Imm;
}]>;
// Addressing modes
def FrameADDR_ri : ComplexPattern<i32, 2, "SelectFrameADDR_ri",
[add, frameindex], []>;
def AddrModeS9 : ComplexPattern<i32, 2, "SelectAddrModeS9", []>;
def AddrModeImm : ComplexPattern<i32, 2, "SelectAddrModeImm", []>;
def AddrModeFar : ComplexPattern<i32, 2, "SelectAddrModeFar", []>;
//===----------------------------------------------------------------------===//
// Instruction Class Templates
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Pseudo Instructions
//===----------------------------------------------------------------------===//
let Defs = [SP], Uses = [SP] in {
def ADJCALLSTACKDOWN : PseudoInstARC<(outs), (ins i32imm:$amt, i32imm:$amt2),
"# ADJCALLSTACKDOWN $amt, $amt2",
[(callseq_start timm:$amt, timm:$amt2)]>;
def ADJCALLSTACKUP : PseudoInstARC<(outs), (ins i32imm:$amt1, i32imm:$amt2),
"# ADJCALLSTACKUP $amt1",
[(callseq_end timm:$amt1, timm:$amt2)]>;
}
def GETFI : PseudoInstARC<(outs GPR32:$dst), (ins MEMii:$addr),
"pldfi $dst, $addr",
[(set GPR32:$dst, FrameADDR_ri:$addr)]>;
def ST_FAR : PseudoInstARC<(outs), (ins GPR32:$dst, MEMrlimm:$addr),
"ST_FAR $dst, $addr",
[(store GPR32:$dst, AddrModeFar:$addr)]>;
def STH_FAR : PseudoInstARC<(outs), (ins GPR32:$dst, MEMrlimm:$addr),
"STH_FAR $dst, $addr",
[(truncstorei16 GPR32:$dst, AddrModeFar:$addr)]>;
def STB_FAR : PseudoInstARC<(outs), (ins GPR32:$dst, MEMrlimm:$addr),
"STB_FAR $dst, $addr",
[(truncstorei8 GPR32:$dst, AddrModeFar:$addr)]>;
//===----------------------------------------------------------------------===//
// Instruction Generation multiclasses.
// Generate many variants of a single instruction with a single defining
// multiclass. These classes do not contain Selection DAG patterns.
//===----------------------------------------------------------------------===//
// Generic 3 operand binary instructions (i.e., add, r0, r1, r2).
multiclass ArcBinaryInst<bits<5> major, bits<6> mincode,
string opasm> {
// 3 register variant.
def _rrr : F32_DOP_RR<major, mincode, 0, (outs GPR32:$A),
(ins GPR32:$B, GPR32:$C),
!strconcat(opasm, "\t$A, $B, $C"),
[]>;
// 2 register with unsigned 6-bit immediate variant.
def _rru6 : F32_DOP_RU6<major, mincode, 0, (outs GPR32:$A),
(ins GPR32:$B, immU6:$U6),
!strconcat(opasm, "\t$A, $B, $U6"),
[]>;
// 2 register with 32-bit immediate variant.
def _rrlimm : F32_DOP_RLIMM<major, mincode, 0,
(outs GPR32:$A),
(ins GPR32:$B, i32imm:$LImm),
!strconcat(opasm, "\t$A, $B, $LImm"),
[]>;
// 2 matched-register with signed 12-bit immediate variant (add r0, r0, -1).
def _rrs12 : F32_DOP_RS12<major, mincode, 0,
(outs GPR32:$B),
(ins GPR32:$in, immS12:$S12),
!strconcat(opasm, "\t$B, $in, $S12"),
[]>
{ let Constraints = "$B = $in"; }
}
// Special multivariant GEN4 DOP format instruction that take 2 registers.
// This is the class that is used for various comparison instructions.
multiclass ArcSpecialDOPInst<bits<6> subop, string opasm, bit F> {
def _rr : F32_DOP_RR<0b00100, subop, F, (outs), (ins GPR32:$B, GPR32:$C),
!strconcat(opasm, "\t$B, $C"),
[]>;
def _ru6 : F32_DOP_RU6<0b00100, subop, F, (outs), (ins GPR32:$B, i32imm:$U6),
!strconcat(opasm, "\t$B, $U6"),
[]>;
def _rlimm : F32_DOP_RLIMM<0b00100, subop, F, (outs),
(ins GPR32:$B, i32imm:$LImm),
!strconcat(opasm, "\t$B, $LImm"),
[]>;
}
// Generic 2-operand unary instructions.
multiclass ArcUnaryInst<bits<5> major, bits<6> subop,
string opasm> {
def _rr : F32_SOP_RR<major, subop, 0, (outs GPR32:$B), (ins GPR32:$C),
!strconcat(opasm, "\t$B, $C"), []>;
}
multiclass ArcBinaryGEN4Inst<bits<6> mincode, string opasm> :
ArcBinaryInst<0b00100, mincode, opasm>;
multiclass ArcBinaryEXT5Inst<bits<6> mincode, string opasm> :
ArcBinaryInst<0b00101, mincode, opasm>;
multiclass ArcUnaryGEN4Inst<bits<6> mincode, string opasm> :
ArcUnaryInst<0b00100, mincode, opasm>;
// Pattern generation for differnt instruction variants.
multiclass MultiPat<SDPatternOperator InFrag,
Instruction RRR, Instruction RRU6, Instruction RRLImm> {
def _rrr : Pat<(InFrag i32:$B, i32:$C), (RRR i32:$B, i32:$C)>;
def _rru6 : Pat<(InFrag i32:$B, immU6:$U6), (RRU6 i32:$B, immU6:$U6)>;
def _rrlimm : Pat<(InFrag i32:$B, imm32:$LImm), (RRLImm i32:$B, imm32:$LImm)>;
}
// ---------------------------------------------------------------------------
// Instruction defintions and patterns for 3 operand binary instructions.
// ---------------------------------------------------------------------------
// Definitions for 3 operand binary instructions.
defm ADD : ArcBinaryGEN4Inst<0b000000, "add">;
defm SUB : ArcBinaryGEN4Inst<0b000010, "sub">;
defm OR : ArcBinaryGEN4Inst<0b000101, "or">;
defm AND : ArcBinaryGEN4Inst<0b000100, "and">;
defm XOR : ArcBinaryGEN4Inst<0b000111, "xor">;
defm MAX : ArcBinaryGEN4Inst<0b001000, "max">;
defm MIN : ArcBinaryGEN4Inst<0b001001, "min">;
defm ASL : ArcBinaryEXT5Inst<0b000000, "asl">;
defm LSR : ArcBinaryEXT5Inst<0b000001, "lsr">;
defm ASR : ArcBinaryEXT5Inst<0b000010, "asr">;
defm ROR : ArcBinaryEXT5Inst<0b000011, "ror">;
defm MPY : ArcBinaryGEN4Inst<0b011010, "mpy">;
defm MPYM : ArcBinaryGEN4Inst<0b011011, "mpym">;
defm MPYMU : ArcBinaryGEN4Inst<0b011100, "mpymu">;
// Patterns for 3 operand binary instructions.
defm : MultiPat<add, ADD_rrr, ADD_rru6, ADD_rrlimm>;
defm : MultiPat<sub, SUB_rrr, SUB_rru6, SUB_rrlimm>;
defm : MultiPat<or, OR_rrr, OR_rru6, OR_rrlimm>;
defm : MultiPat<and, AND_rrr, AND_rru6, AND_rrlimm>;
defm : MultiPat<xor, XOR_rrr, XOR_rru6, XOR_rrlimm>;
defm : MultiPat<smax, MAX_rrr, MAX_rru6, MAX_rrlimm>;
defm : MultiPat<smin, MIN_rrr, MIN_rru6, MIN_rrlimm>;
defm : MultiPat<shl, ASL_rrr, ASL_rru6, ASL_rrlimm>;
defm : MultiPat<srl, LSR_rrr, LSR_rru6, LSR_rrlimm>;
defm : MultiPat<sra, ASR_rrr, ASR_rru6, ASR_rrlimm>;
defm : MultiPat<rotr, ROR_rrr, ROR_rru6, ROR_rrlimm>;
defm : MultiPat<mul, MPY_rrr, MPY_rru6, MPY_rrlimm>;
defm : MultiPat<mulhs, MPYM_rrr, MPYM_rru6, MPYM_rrlimm>;
defm : MultiPat<mulhu, MPYMU_rrr, MPYMU_rru6, MPYMU_rrlimm>;
// ---------------------------------------------------------------------------
// Unary Instruction definitions.
// ---------------------------------------------------------------------------
// General unary instruction definitions.
defm SEXB : ArcUnaryGEN4Inst<0b000101, "sexb">;
defm SEXH : ArcUnaryGEN4Inst<0b000110, "sexh">;
// General Unary Instruction fragments.
def : Pat<(sext_inreg i32:$a, i8), (SEXB_rr i32:$a)>;
def : Pat<(sext_inreg i32:$a, i16), (SEXH_rr i32:$a)>;
// Comparison instruction definition
let isCompare = 1, Defs = [STATUS32] in {
defm CMP : ArcSpecialDOPInst<0b001100, "cmp", 1>;
}
def cmp : PatFrag<(ops node:$op1, node:$op2), (ARCcmp $op1, $op2)>;
defm : MultiPat<cmp, CMP_rr, CMP_ru6, CMP_rlimm>;
// ---------------------------------------------------------------------------
// MOV instruction and variants (conditional mov).
// ---------------------------------------------------------------------------
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in {
def MOV_rs12 : F32_DOP_RS12<0b00100, 0b001010, 0,
(outs GPR32:$B), (ins immS12:$S12),
"mov\t$B, $S12",
[(set GPR32:$B, immS12:$S12)]>;
}
def MOV_rr : F32_DOP_RR<0b00100, 0b001010, 0,
(outs GPR32:$B), (ins GPR32:$C),
"mov\t$B, $C", []>;
def MOV_rlimm : F32_DOP_RLIMM<0b00100, 0b001010, 0,
(outs GPR32:$B), (ins i32imm:$LImm),
"mov\t$B, $LImm", []>;
def MOV_ru6 : F32_DOP_RU6<0b00100, 0b001010, 0,
(outs GPR32:$B), (ins immU6:$U6),
"mov\t$B, $U6", []>;
def cmov : PatFrag<(ops node:$op1, node:$op2, node:$cc),
(ARCcmov $op1, $op2, $cc)>;
let Uses = [STATUS32] in {
def MOVcc : F32_DOP_CC_RR<0b00100, 0b001010, 0,
(outs GPR32:$B),
(ins GPR32:$C, GPR32:$fval, cmovpred:$cc),
!strconcat("mov.", "$cc\t$B, $C"),
[(set GPR32:$B, (cmov i32:$C, i32:$fval, cmovpred:$cc))]> {
let Constraints = "$B = $fval";
}
}
def : Pat<(ARCGAWrapper tglobaladdr:$addr),
(MOV_rlimm tglobaladdr:$addr)>;
def : Pat<(ARCGAWrapper tjumptable:$addr),
(MOV_rlimm tjumptable:$addr)>;
// ---------------------------------------------------------------------------
// Control flow instructions (branch, return, calls, etc).
// ---------------------------------------------------------------------------
// Branch instructions
let isBranch = 1, isTerminator = 1, isBarrier = 1 in {
// Unconditional branch.
def BR : F32_BR0_UCOND_FAR<(outs), (ins btargetS25:$S25),
"b\t$S25", [(br bb:$S25)]>;
let Uses=[STATUS32] in {
// Conditional branch.
def Bcc : F32_BR0_COND<(outs), (ins btargetS21:$S21, ccond:$cc),
"b$cc\t$S21", []>;
}
// Compare and branch (limited range).
def BRcc_rr : F32_BR1_BCC<(outs),
(ins btargetS9:$S9, GPR32:$B, GPR32:$C, brccond:$cc),
"br$cc\t$B, $C, $S9", 0, []>;
def BRcc_ru6 : F32_BR1_BCC<(outs),
(ins btargetS9:$S9, GPR32:$B, immU6:$C, brccond:$cc),
"br$cc\t$B, $C, $S9", 1, []>;
// Pseudo compare and branch.
// After register allocation, this can expand into either a limited range
// Compare and branch (BRcc), or into CMP + Bcc.
// At worst, this expands into 2 4-byte instructions.
def BRcc_rr_p : PseudoInstARC<(outs),
(ins btarget:$T, GPR32:$B, GPR32:$C, ccond:$cc),
"pbr$cc\t$B, $C, $T",
[(ARCbrcc bb:$T, i32:$B, i32:$C, imm32:$cc)]>
{ let Size = 8; }
def BRcc_ru6_p : PseudoInstARC<(outs),
(ins btarget:$T, GPR32:$B, i32imm:$C, ccond:$cc),
"pbr$cc\t$B, $C, $T",
[(ARCbrcc bb:$T, i32:$B, immU6:$C, imm32:$cc)]>
{ let Size = 8; }
}
// Indirect, unconditional Jump.
let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in {
def J : F32_DOP_RR<0b00100, 0b100000, 0,
(outs), (ins GPR32:$C),
"j\t[$C]", [(brind i32:$C)]>;
}
// Call instructions.
let isCall = 1, Defs = [BLINK], Uses = [SP] in {
// Direct unconditional call.
def BL : F32_BR1_BL_UCOND_FAR<(outs), (ins calltargetS25:$S25),
"bl\t$S25", [(ARCBranchLink tglobaladdr:$S25)]>;
// Indirect unconditional call.
let isIndirectBranch = 1, Defs = [BLINK], Uses = [SP] in {
def JL : F32_DOP_RR<0b00100, 0b100010, 0, (outs), (ins GPR32:$C),
"jl\t[$C]", [(ARCJumpLink i32:$C)]>;
}
}
// Pattern to generate BL instruction.
def : Pat<(ARCBranchLink texternalsym:$dst), (BL texternalsym:$dst)>;
// Return from call.
let isReturn = 1, isTerminator = 1, isBarrier = 1 in {
// This is a specialized 2-byte instruction that doesn't generalize
// to any larger 2-byte class, so go ahead and define it here.
def J_S_BLINK : InstARC<2, (outs), (ins), "j_s\t[%blink]", [(ret)]> {
let Inst{15-0} = 0b0111111011100000;
}
}
//----------------------------------------------------------------------------
// Load/Store instructions.
//----------------------------------------------------------------------------
// 2-byte push/pop blink instructions commonly used for prolog/epilog
// generation. These 2 instructions are actually specialized 2-byte
// format instructions that aren't generalized to a larger 2-byte
// class, so we might as well have them here.
let Uses = [BLINK], Defs = [SP] in {
def PUSH_S_BLINK : InstARC<2, (outs), (ins),
"push_s\t%blink", []> {
let Inst{15-0} = 0b1100000011110001;
}
}
let Defs = [BLINK, SP] in {
def POP_S_BLINK : InstARC<2, (outs), (ins),
"pop_s\t%blink", []> {
let Inst{15-0} = 0b1100000011010001;
}
}
// Load instruction variants:
// Control bits: x, aa, di, zz
// x - sign extend.
// aa - incrementing mode. (N/A for LIMM).
// di - uncached.
// zz - data size.
multiclass ArcLdInst<bits<2> zz, string asmop> {
let mayLoad = 1 in {
def _rs9 : F32_LD_ADDR<0, 0b00, 0, zz,
(outs GPR32:$A), (ins MEMrs9:$addr),
!strconcat(asmop, "\t$A, [$addr]"), []>;
def _limm : F32_LD_LIMM<0, 0, zz,
(outs GPR32:$A), (ins MEMii:$addr),
!strconcat(asmop, "\t$A, [$addr]"), []>;
def _rlimm : F32_LD_RLIMM<0, 0b00, 0, zz,
(outs GPR32:$A), (ins MEMrlimm:$addr),
!strconcat(asmop, "\t$A, [$addr]"), []>;
def _X_rs9 : F32_LD_ADDR<1, 0b00, 0, zz,
(outs GPR32:$A), (ins MEMrs9:$addr),
!strconcat(asmop, ".x\t$A, [$addr]"), []>;
def _X_limm : F32_LD_LIMM<1, 0, zz,
(outs GPR32:$A), (ins MEMii:$addr),
!strconcat(asmop, ".x\t$A, [$addr]"), []>;
def _X_rlimm : F32_LD_RLIMM<1, 0b00, 0, zz,
(outs GPR32:$A), (ins MEMrlimm:$addr),
!strconcat(asmop, ".x\t$A, [$addr]"), []>;
def _AB_rs9 : F32_LD_RS9<0, 0b10, 0, zz,
(outs GPR32:$addrout, GPR32:$A),
(ins GPR32:$B, immS9:$S9),
!strconcat(asmop, ".ab\t$A, [$B,$S9]"), []>
{ let Constraints = "$addrout = $B"; }
}
}
// Load instruction definitions.
defm LD : ArcLdInst<0b00, "ld">;
defm LDH : ArcLdInst<0b10, "ldh">;
defm LDB : ArcLdInst<0b01, "ldb">;
// Load instruction patterns.
// 32-bit loads.
def : Pat<(load AddrModeS9:$addr), (LD_rs9 AddrModeS9:$addr)>;
def : Pat<(load AddrModeImm:$addr), (LD_limm AddrModeImm:$addr)>;
def : Pat<(load AddrModeFar:$addr), (LD_rs9 AddrModeFar:$addr)>;
// 16-bit loads
def : Pat<(zextloadi16 AddrModeS9:$addr), (LDH_rs9 AddrModeS9:$addr)>;
def : Pat<(extloadi16 AddrModeS9:$addr), (LDH_rs9 AddrModeS9:$addr)>;
def : Pat<(zextloadi16 AddrModeImm:$addr), (LDH_limm AddrModeImm:$addr)>;
def : Pat<(extloadi16 AddrModeImm:$addr), (LDH_limm AddrModeImm:$addr)>;
def : Pat<(zextloadi16 AddrModeFar:$addr), (LDH_rlimm AddrModeFar:$addr)>;
def : Pat<(extloadi16 AddrModeFar:$addr), (LDH_rlimm AddrModeFar:$addr)>;
def : Pat<(sextloadi16 AddrModeImm:$addr),(LDH_X_limm AddrModeImm:$addr)>;
def : Pat<(sextloadi16 AddrModeFar:$addr),(LDH_X_rlimm AddrModeFar:$addr)>;
def : Pat<(sextloadi16 AddrModeS9:$addr),(LDH_X_rs9 AddrModeS9:$addr)>;
// 8-bit loads.
def : Pat<(zextloadi8 AddrModeS9:$addr), (LDB_rs9 AddrModeS9:$addr)>;
def : Pat<(extloadi8 AddrModeS9:$addr), (LDB_rs9 AddrModeS9:$addr)>;
def : Pat<(zextloadi8 AddrModeImm:$addr), (LDB_limm AddrModeImm:$addr)>;
def : Pat<(extloadi8 AddrModeImm:$addr), (LDB_limm AddrModeImm:$addr)>;
def : Pat<(zextloadi8 AddrModeFar:$addr), (LDB_rlimm AddrModeFar:$addr)>;
def : Pat<(extloadi8 AddrModeFar:$addr), (LDB_rlimm AddrModeFar:$addr)>;
def : Pat<(zextloadi1 AddrModeS9:$addr), (LDB_rs9 AddrModeS9:$addr)>;
def : Pat<(extloadi1 AddrModeS9:$addr), (LDB_rs9 AddrModeS9:$addr)>;
def : Pat<(zextloadi1 AddrModeImm:$addr), (LDB_limm AddrModeImm:$addr)>;
def : Pat<(extloadi1 AddrModeImm:$addr), (LDB_limm AddrModeImm:$addr)>;
def : Pat<(zextloadi1 AddrModeFar:$addr), (LDB_rlimm AddrModeFar:$addr)>;
def : Pat<(extloadi1 AddrModeFar:$addr), (LDB_rlimm AddrModeFar:$addr)>;
def : Pat<(sextloadi8 AddrModeImm:$addr),(LDB_X_limm AddrModeImm:$addr)>;
def : Pat<(sextloadi8 AddrModeFar:$addr),(LDB_X_rlimm AddrModeFar:$addr)>;
def : Pat<(sextloadi8 AddrModeS9:$addr),(LDB_X_rs9 AddrModeS9:$addr)>;
// Store instruction variants:
// Control bits: aa, di, zz
// aa - incrementing mode. (N/A for LIMM).
// di - uncached.
// zz - data size.
multiclass ArcStInst<bits<2> zz, string asmop> {
let mayStore = 1 in {
def _rs9 : F32_ST_ADDR<0b00, 0, zz, (outs), (ins GPR32:$C, MEMrs9:$addr),
!strconcat(asmop, "\t$C, [$addr]"), []>;
def _limm : F32_ST_LIMM<0, zz, (outs), (ins GPR32:$C, MEMii:$addr),
!strconcat(asmop, "\t$C, [$addr]"), []>;
def _AW_rs9 : F32_ST_RS9<0b01, 0, zz, (outs GPR32:$addrout),
(ins GPR32:$C, GPR32:$B, immS9:$S9),
!strconcat(asmop, ".aw\t$C, [$B,$S9]"), []>
{ let Constraints = "$addrout = $B"; }
}
}
// Store instruction definitions.
defm ST : ArcStInst<0b00, "st">;
defm STH : ArcStInst<0b10, "sth">;
defm STB : ArcStInst<0b01, "stb">;
// Store instruction patterns.
// 32-bit stores
def : Pat<(store i32:$C, AddrModeS9:$addr),
(ST_rs9 i32:$C, AddrModeS9:$addr)>;
def : Pat<(store i32:$C, AddrModeImm:$addr),
(ST_limm i32:$C, AddrModeImm:$addr)>;
// 16-bit stores
def : Pat<(truncstorei16 i32:$C, AddrModeS9:$addr),
(STH_rs9 i32:$C, AddrModeS9:$addr)>;
def : Pat<(truncstorei16 i32:$C, AddrModeImm:$addr),
(STH_limm i32:$C, AddrModeImm:$addr)>;
// 8-bit stores
def : Pat<(truncstorei8 i32:$C, AddrModeS9:$addr),
(STB_rs9 i32:$C, AddrModeS9:$addr)>;
def : Pat<(truncstorei8 i32:$C, AddrModeImm:$addr),
(STB_limm i32:$C, AddrModeImm:$addr)>;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMARCDisassembler
ARCDisassembler.cpp
)

View File

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

View File

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

View File

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

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMARCAsmPrinter
ARCInstPrinter.cpp
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,103 @@
//===- ARCMCTargetDesc.cpp - ARC Target Descriptions ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides ARC specific target descriptions.
//
//===----------------------------------------------------------------------===//
#include "ARCMCTargetDesc.h"
#include "ARCMCAsmInfo.h"
#include "ARCTargetStreamer.h"
#include "InstPrinter/ARCInstPrinter.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
#define GET_INSTRINFO_MC_DESC
#include "ARCGenInstrInfo.inc"
#define GET_SUBTARGETINFO_MC_DESC
#include "ARCGenSubtargetInfo.inc"
#define GET_REGINFO_MC_DESC
#include "ARCGenRegisterInfo.inc"
static MCInstrInfo *createARCMCInstrInfo() {
auto *X = new MCInstrInfo();
InitARCMCInstrInfo(X);
return X;
}
static MCRegisterInfo *createARCMCRegisterInfo(const Triple &TT) {
auto *X = new MCRegisterInfo();
InitARCMCRegisterInfo(X, ARC::BLINK);
return X;
}
static MCSubtargetInfo *createARCMCSubtargetInfo(const Triple &TT,
StringRef CPU, StringRef FS) {
return createARCMCSubtargetInfoImpl(TT, CPU, FS);
}
static MCAsmInfo *createARCMCAsmInfo(const MCRegisterInfo &MRI,
const Triple &TT) {
MCAsmInfo *MAI = new ARCMCAsmInfo(TT);
// Initial state of the frame pointer is SP.
MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, ARC::SP, 0);
MAI->addInitialFrameState(Inst);
return MAI;
}
static MCInstPrinter *createARCMCInstPrinter(const Triple &T,
unsigned SyntaxVariant,
const MCAsmInfo &MAI,
const MCInstrInfo &MII,
const MCRegisterInfo &MRI) {
return new ARCInstPrinter(MAI, MII, MRI);
}
ARCTargetStreamer::ARCTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
ARCTargetStreamer::~ARCTargetStreamer() = default;
static MCTargetStreamer *createTargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &OS,
MCInstPrinter *InstPrint,
bool isVerboseAsm) {
return new ARCTargetStreamer(S);
}
// Force static initialization.
extern "C" void LLVMInitializeARCTargetMC() {
// Register the MC asm info.
Target &TheARCTarget = getTheARCTarget();
RegisterMCAsmInfoFn X(TheARCTarget, createARCMCAsmInfo);
// Register the MC instruction info.
TargetRegistry::RegisterMCInstrInfo(TheARCTarget, createARCMCInstrInfo);
// Register the MC register info.
TargetRegistry::RegisterMCRegInfo(TheARCTarget, createARCMCRegisterInfo);
// Register the MC subtarget info.
TargetRegistry::RegisterMCSubtargetInfo(TheARCTarget,
createARCMCSubtargetInfo);
// Register the MCInstPrinter
TargetRegistry::RegisterMCInstPrinter(TheARCTarget, createARCMCInstPrinter);
TargetRegistry::RegisterAsmTargetStreamer(TheARCTarget,
createTargetAsmStreamer);
}

View File

@ -0,0 +1,39 @@
//===- ARCMCTargetDesc.h - ARC Target Descriptions --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides ARC specific target descriptions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCMCTARGETDESC_H
#define LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCMCTARGETDESC_H
#include "llvm/Support/DataTypes.h"
namespace llvm {
class Target;
Target &getTheARCTarget();
} // end namespace llvm
// Defines symbolic names for ARC registers. This defines a mapping from
// register name to register number.
#define GET_REGINFO_ENUM
#include "ARCGenRegisterInfo.inc"
// Defines symbolic names for the ARC instructions.
#define GET_INSTRINFO_ENUM
#include "ARCGenInstrInfo.inc"
#define GET_SUBTARGETINFO_ENUM
#include "ARCGenSubtargetInfo.inc"
#endif // LLVM_LIB_TARGET_ARC_MCTARGETDESC_ARCMCTARGETDESC_H

View File

@ -0,0 +1,4 @@
add_llvm_library(LLVMARCDesc
ARCMCTargetDesc.cpp
ARCMCAsmInfo.cpp
)

View File

@ -0,0 +1,23 @@
;===- ./lib/Target/ARC/MCTargetDesc/LLVMBuild.txt ------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = ARCDesc
parent = ARC
required_libraries = MC Support ARCAsmPrinter ARCInfo
add_to_library_groups = ARC

View File

@ -0,0 +1,22 @@
//===- ARCTargetInfo.cpp - ARC Target Implementation ----------- *- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ARC.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
Target &llvm::getTheARCTarget() {
static Target TheARCTarget;
return TheARCTarget;
}
extern "C" void LLVMInitializeARCTargetInfo() {
RegisterTarget<Triple::arc> X(getTheARCTarget(), "arc", "ARC");
}

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMARCInfo
ARCTargetInfo.cpp
)

View File

@ -0,0 +1,23 @@
;===- ./lib/Target/ARC/TargetInfo/LLVMBuild.txt --------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = ARCInfo
parent = ARC
required_libraries = Support
add_to_library_groups = ARC

View File

@ -20,6 +20,7 @@
[common]
subdirectories =
AMDGPU
ARC
ARM
AArch64
AVR

255
test/CodeGen/ARC/alu.ll Normal file
View File

@ -0,0 +1,255 @@
; RUN: llc -march=arc < %s | FileCheck %s
; CHECK-LABEL: add_r
; CHECK: add %r0, %r{{[01]}}, %r{{[01]}}
define i32 @add_r(i32 %a, i32 %b) nounwind {
entry:
%v = add i32 %a, %b
ret i32 %v
}
; CHECK-LABEL: add_u6
; CHECK: add %r0, %r0, 15
define i32 @add_u6(i32 %a) nounwind {
%v = add i32 %a, 15
ret i32 %v
}
; CHECK-LABEL: add_limm
; CHECK: add %r0, %r0, 12345
define i32 @add_limm(i32 %a) nounwind {
%v = add i32 %a, 12345
ret i32 %v
}
; CHECK-LABEL: mpy_r
; CHECK: mpy %r0, %r{{[01]}}, %r{{[01]}}
define i32 @mpy_r(i32 %a, i32 %b) nounwind {
entry:
%v = mul i32 %a, %b
ret i32 %v
}
; CHECK-LABEL: mpy_u6
; CHECK: mpy %r0, %r0, 10
define i32 @mpy_u6(i32 %a) nounwind {
%v = mul i32 %a, 10
ret i32 %v
}
; CHECK-LABEL: mpy_limm
; CHECK: mpy %r0, %r0, 12345
define i32 @mpy_limm(i32 %a) nounwind {
%v = mul i32 %a, 12345
ret i32 %v
}
; CHECK-LABEL: max_r
; CHECK: max %r0, %r{{[01]}}, %r{{[01]}}
define i32 @max_r(i32 %a, i32 %b) nounwind {
%i = icmp sgt i32 %a, %b
%v = select i1 %i, i32 %a, i32 %b
ret i32 %v
}
; CHECK-LABEL: max_u6
; CHECK: max %r0, %r0, 12
define i32 @max_u6(i32 %a) nounwind {
%i = icmp sgt i32 %a, 12
%v = select i1 %i, i32 %a, i32 12
ret i32 %v
}
; CHECK-LABEL: max_limm
; CHECK: max %r0, %r0, 2345
define i32 @max_limm(i32 %a) nounwind {
%i = icmp sgt i32 %a, 2345
%v = select i1 %i, i32 %a, i32 2345
ret i32 %v
}
; CHECK-LABEL: min_r
; CHECK: min %r0, %r{{[01]}}, %r{{[01]}}
define i32 @min_r(i32 %a, i32 %b) nounwind {
%i = icmp slt i32 %a, %b
%v = select i1 %i, i32 %a, i32 %b
ret i32 %v
}
; CHECK-LABEL: min_u6
; CHECK: min %r0, %r0, 20
define i32 @min_u6(i32 %a) nounwind {
%i = icmp slt i32 %a, 20
%v = select i1 %i, i32 %a, i32 20
ret i32 %v
}
; CHECK-LABEL: min_limm
; CHECK: min %r0, %r0, 2040
define i32 @min_limm(i32 %a) nounwind {
%i = icmp slt i32 %a, 2040
%v = select i1 %i, i32 %a, i32 2040
ret i32 %v
}
; CHECK-LABEL: and_r
; CHECK: and %r0, %r{{[01]}}, %r{{[01]}}
define i32 @and_r(i32 %a, i32 %b) nounwind {
%v = and i32 %a, %b
ret i32 %v
}
; CHECK-LABEL: and_u6
; CHECK: and %r0, %r0, 7
define i32 @and_u6(i32 %a) nounwind {
%v = and i32 %a, 7
ret i32 %v
}
; 0xfffff == 1048575
; CHECK-LABEL: and_limm
; CHECK: and %r0, %r0, 1048575
define i32 @and_limm(i32 %a) nounwind {
%v = and i32 %a, 1048575
ret i32 %v
}
; CHECK-LABEL: or_r
; CHECK: or %r0, %r{{[01]}}, %r{{[01]}}
define i32 @or_r(i32 %a, i32 %b) nounwind {
%v = or i32 %a, %b
ret i32 %v
}
; CHECK-LABEL: or_u6
; CHECK: or %r0, %r0, 7
define i32 @or_u6(i32 %a) nounwind {
%v = or i32 %a, 7
ret i32 %v
}
; 0xf0f0f == 986895
; CHECK-LABEL: or_limm
define i32 @or_limm(i32 %a) nounwind {
%v = or i32 %a, 986895
ret i32 %v
}
; CHECK-LABEL: xor_r
; CHECK: xor %r0, %r{{[01]}}, %r{{[01]}}
define i32 @xor_r(i32 %a, i32 %b) nounwind {
%v = xor i32 %a, %b
ret i32 %v
}
; CHECK-LABEL: xor_u6
; CHECK: xor %r0, %r0, 3
define i32 @xor_u6(i32 %a) nounwind {
%v = xor i32 %a, 3
ret i32 %v
}
; CHECK-LABEL: xor_limm
; CHECK: xor %r0, %r0, 986895
define i32 @xor_limm(i32 %a) nounwind {
%v = xor i32 %a, 986895
ret i32 %v
}
; CHECK-LABEL: asl_r
; CHECK: asl %r0, %r{{[01]}}, %r{{[01]}}
define i32 @asl_r(i32 %a, i32 %b) nounwind {
%v = shl i32 %a, %b
ret i32 %v
}
; CHECK-LABEL: asl_u6
; CHECK: asl %r0, %r0, 4
define i32 @asl_u6(i32 %a) nounwind {
%v = shl i32 %a, 4
ret i32 %v
}
; CHECK-LABEL: lsr_r
; CHECK: lsr %r0, %r{{[01]}}, %r{{[01]}}
define i32 @lsr_r(i32 %a, i32 %b) nounwind {
%v = lshr i32 %a, %b
ret i32 %v
}
; CHECK-LABEL: lsr_u6
; CHECK: lsr %r0, %r0, 6
define i32 @lsr_u6(i32 %a) nounwind {
%v = lshr i32 %a, 6
ret i32 %v
}
; CHECK-LABEL: asr_r
; CHECK: asr %r0, %r{{[01]}}, %r{{[01]}}
define i32 @asr_r(i32 %a, i32 %b) nounwind {
%v = ashr i32 %a, %b
ret i32 %v
}
; CHECK-LABEL: asr_u6
; CHECK: asr %r0, %r0, 8
define i32 @asr_u6(i32 %a) nounwind {
%v = ashr i32 %a, 8
ret i32 %v
}
; CHECK-LABEL: ror_r
; CHECK: ror %r0, %r{{[01]}}, %r{{[01]}}
define i32 @ror_r(i32 %a, i32 %b) nounwind {
%v1 = lshr i32 %a, %b
%ls = sub i32 32, %b
%v2 = shl i32 %a, %ls
%v = or i32 %v1, %v2
ret i32 %v
}
; CHECK-LABEL: ror_u6
; CHECK: ror %r0, %r0, 10
define i32 @ror_u6(i32 %a) nounwind {
%v1 = lshr i32 %a, 10
%v2 = shl i32 %a, 22
%v = or i32 %v1, %v2
ret i32 %v
}
; CHECK-LABEL: sexh_r
; CHECK: sexh %r0, %r0
define i32 @sexh_r(i32 %a) nounwind {
%v1 = shl i32 %a, 16
%v = ashr i32 %v1, 16
ret i32 %v
}
; CHECK-LABEL: sexb_r
; CHECK: sexb %r0, %r0
define i32 @sexb_r(i32 %a) nounwind {
%v1 = shl i32 %a, 24
%v = ashr i32 %v1, 24
ret i32 %v
}
; CHECK-LABEL: mulu64
; CHECK-DAG: mpy %r[[REG:[0-9]+]], %r{{[01]}}, %r{{[01]}}
; CHECK-DAG: mpymu %r[[REG:[0-9]+]], %r{{[01]}}, %r{{[01]}}
define i64 @mulu64(i32 %a, i32 %b) nounwind {
%a64 = zext i32 %a to i64
%b64 = zext i32 %b to i64
%v = mul i64 %a64, %b64
ret i64 %v
}
; CHECK-LABEL: muls64
; CHECK-DAG: mpy %r[[REG:[0-9]+]], %r{{[01]}}, %r{{[01]}}
; CHECK-DAG: mpym %r[[REG:[0-9]+]], %r{{[01]}}, %r{{[01]}}
define i64 @muls64(i32 %a, i32 %b) nounwind {
%a64 = sext i32 %a to i64
%b64 = sext i32 %b to i64
%v = mul i64 %a64, %b64
ret i64 %v
}

37
test/CodeGen/ARC/brcc.ll Normal file
View File

@ -0,0 +1,37 @@
; RUN: llc -march=arc < %s | FileCheck %s
; CHECK-LABEL: brcc1
; CHECK: brne %r0, %r1
define i32 @brcc1(i32 %a, i32 %b) nounwind {
entry:
%wb = icmp eq i32 %a, %b
br i1 %wb, label %t1, label %t2
t1:
%t1v = add i32 %a, 4
br label %exit
t2:
%t2v = add i32 %b, 8
br label %exit
exit:
%v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
ret i32 %v
}
; CHECK-LABEL: brcc2
; CHECK: breq %r0, %r1
define i32 @brcc2(i32 %a, i32 %b) nounwind {
entry:
%wb = icmp ne i32 %a, %b
br i1 %wb, label %t1, label %t2
t1:
%t1v = add i32 %a, 4
br label %exit
t2:
%t2v = add i32 %b, 8
br label %exit
exit:
%v = phi i32 [ %t1v, %t1 ], [ %t2v, %t2 ]
ret i32 %v
}

88
test/CodeGen/ARC/call.ll Normal file
View File

@ -0,0 +1,88 @@
; RUN: llc -march=arc < %s | FileCheck %s
declare i32 @goo1(i32) nounwind
; CHECK-LABEL: call1
; CHECK: bl @goo1
define i32 @call1(i32 %a) nounwind {
entry:
%x = call i32 @goo1(i32 %a)
ret i32 %x
}
declare i32 @goo2(i32, i32, i32, i32, i32, i32, i32, i32) nounwind
; CHECK-LABEL: call2
; CHECK-DAG: mov %r0, 0
; CHECK-DAG: mov %r1, 1
; CHECK-DAG: mov %r2, 2
; CHECK-DAG: mov %r3, 3
; CHECK-DAG: mov %r4, 4
; CHECK-DAG: mov %r5, 5
; CHECK-DAG: mov %r6, 6
; CHECK-DAG: mov %r7, 7
; CHECK: bl @goo2
define i32 @call2() nounwind {
entry:
%x = call i32 @goo2(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7)
ret i32 %x
}
declare i32 @goo3(i64, i32, i64) nounwind
; call goo3(0xEEEEEEEE77777777, 0x55555555, 0xAAAAAAAA33333333)
; 0xEEEEEEEE == -286331154
; 0x77777777 == 2004318071
; 0x55555555 == 1431655765
; 0xAAAAAAAA == -1431655766
; 0x33333333 == 858993459
; CHECK-LABEL: call3
; CHECK-DAG: mov %r0, 2004318071
; CHECK-DAG: mov %r1, -286331154
; CHECK-DAG: mov %r2, 1431655765
; CHECK-DAG: mov %r3, 858993459
; CHECK-DAG: mov %r4, -1431655766
; CHECK: bl @goo3
define i32 @call3() nounwind {
entry:
%x = call i32 @goo3(i64 17216961133457930103,
i32 1431655765,
i64 12297829380468716339)
ret i32 %x
}
declare i64 @goo4()
; 64-bit values are returned in r0r1
; CHECK-LABEL: call4
; CHECK: bl @goo4
; CHECK: lsr %r0, %r1, 16
define i32 @call4() nounwind {
%x = call i64 @goo4()
%v1 = lshr i64 %x, 48
%v = trunc i64 %v1 to i32
ret i32 %v
}
; 0x0000ffff00ff00ff=281470698455295
; returned as r0=0x00ff00ff=16711935, r1=0x0000ffff=65535
; CHECK-LABEL: ret1
; CHECK-DAG: mov %r1, 65535
; CHECK-DAG: mov %r0, 16711935
define i64 @ret1() nounwind {
ret i64 281470698455295
}
@funcptr = external global i32 (i32)*, align 4
; Indirect calls use JL
; CHECK-LABEL: call_indirect
; CHECK-DAG: ld %r[[REG:[0-9]+]], [@funcptr]
; CHECK-DAG: mov %r0, 12
; CHECK: jl [%r[[REG]]]
define i32 @call_indirect(i32 %x) nounwind {
%f = load i32 (i32)*, i32 (i32)** @funcptr, align 4
%call = call i32 %f(i32 12)
%add = add nsw i32 %call, %x
ret i32 %add
}

272
test/CodeGen/ARC/ldst.ll Normal file
View File

@ -0,0 +1,272 @@
; RUN: llc -march=arc < %s | FileCheck %s
; CHECK-LABEL: load32
; CHECK: ld %r0, [%r0,16000]
define i32 @load32(i32* %bp) nounwind {
entry:
%gep = getelementptr i32, i32* %bp, i32 4000
%v = load i32, i32* %gep, align 4
ret i32 %v
}
; CHECK-LABEL: load16
; CHECK: ldh %r0, [%r0,8000]
define i16 @load16(i16* %bp) nounwind {
entry:
%gep = getelementptr i16, i16* %bp, i32 4000
%v = load i16, i16* %gep, align 2
ret i16 %v
}
; CHECK-LABEL: load8
; CHECK: ldb %r0, [%r0,4000]
define i8 @load8(i8* %bp) nounwind {
entry:
%gep = getelementptr i8, i8* %bp, i32 4000
%v = load i8, i8* %gep, align 1
ret i8 %v
}
; CHECK-LABEL: sextload16
; CHECK: ldh.x %r0, [%r0,8000]
define i32 @sextload16(i16* %bp) nounwind {
entry:
%gep = getelementptr i16, i16* %bp, i32 4000
%vl = load i16, i16* %gep, align 2
%v = sext i16 %vl to i32
ret i32 %v
}
; CHECK-LABEL: sextload8
; CHECK: ldb.x %r0, [%r0,4000]
define i32 @sextload8(i8* %bp) nounwind {
entry:
%gep = getelementptr i8, i8* %bp, i32 4000
%vl = load i8, i8* %gep, align 1
%v = sext i8 %vl to i32
ret i32 %v
}
; CHECK-LABEL: s_sextload16
; CHECK: ldh.x %r0, [%r0,32]
define i32 @s_sextload16(i16* %bp) nounwind {
entry:
%gep = getelementptr i16, i16* %bp, i32 16
%vl = load i16, i16* %gep, align 2
%v = sext i16 %vl to i32
ret i32 %v
}
; CHECK-LABEL: s_sextload8
; CHECK: ldb.x %r0, [%r0,16]
define i32 @s_sextload8(i8* %bp) nounwind {
entry:
%gep = getelementptr i8, i8* %bp, i32 16
%vl = load i8, i8* %gep, align 1
%v = sext i8 %vl to i32
ret i32 %v
}
; CHECK-LABEL: store32
; CHECK: add %r[[REG:[0-9]+]], %r1, 16000
; CHECK: st %r0, [%r[[REG]],0]
; Long range stores (offset does not fit in s9) must be add followed by st.
define void @store32(i32 %val, i32* %bp) nounwind {
entry:
%gep = getelementptr i32, i32* %bp, i32 4000
store i32 %val, i32* %gep, align 4
ret void
}
; CHECK-LABEL: store16
; CHECK: add %r[[REG:[0-9]+]], %r1, 8000
; CHECK: sth %r0, [%r[[REG]],0]
define void @store16(i16 zeroext %val, i16* %bp) nounwind {
entry:
%gep = getelementptr i16, i16* %bp, i32 4000
store i16 %val, i16* %gep, align 2
ret void
}
; CHECK-LABEL: store8
; CHECK: add %r[[REG:[0-9]+]], %r1, 4000
; CHECK: stb %r0, [%r[[REG]],0]
define void @store8(i8 zeroext %val, i8* %bp) nounwind {
entry:
%gep = getelementptr i8, i8* %bp, i32 4000
store i8 %val, i8* %gep, align 1
ret void
}
; Short range stores can be done with [reg, s9].
; CHECK-LABEL: s_store32
; CHECK-NOT: add
; CHECK: st %r0, [%r1,64]
define void @s_store32(i32 %val, i32* %bp) nounwind {
entry:
%gep = getelementptr i32, i32* %bp, i32 16
store i32 %val, i32* %gep, align 4
ret void
}
; CHECK-LABEL: s_store16
; CHECK-NOT: add
; CHECK: sth %r0, [%r1,32]
define void @s_store16(i16 zeroext %val, i16* %bp) nounwind {
entry:
%gep = getelementptr i16, i16* %bp, i32 16
store i16 %val, i16* %gep, align 2
ret void
}
; CHECK-LABEL: s_store8
; CHECK-NOT: add
; CHECK: stb %r0, [%r1,16]
define void @s_store8(i8 zeroext %val, i8* %bp) nounwind {
entry:
%gep = getelementptr i8, i8* %bp, i32 16
store i8 %val, i8* %gep, align 1
ret void
}
@aaaa = internal global [128 x i32] zeroinitializer
@bbbb = internal global [128 x i16] zeroinitializer
@cccc = internal global [128 x i8] zeroinitializer
; CHECK-LABEL: g_store32
; CHECK-NOT: add
; CHECK: st %r0, [@aaaa+64]
define void @g_store32(i32 %val) nounwind {
entry:
store i32 %val, i32* getelementptr inbounds ([128 x i32], [128 x i32]* @aaaa, i32 0, i32 16), align 4
ret void
}
; CHECK-LABEL: g_load32
; CHECK-NOT: add
; CHECK: ld %r0, [@aaaa+64]
define i32 @g_load32() nounwind {
%gep = getelementptr inbounds [128 x i32], [128 x i32]* @aaaa, i32 0, i32 16
%v = load i32, i32* %gep, align 4
ret i32 %v
}
; CHECK-LABEL: g_store16
; CHECK-NOT: add
; CHECK: sth %r0, [@bbbb+32]
define void @g_store16(i16 %val) nounwind {
entry:
store i16 %val, i16* getelementptr inbounds ([128 x i16], [128 x i16]* @bbbb, i16 0, i16 16), align 2
ret void
}
; CHECK-LABEL: g_load16
; CHECK-NOT: add
; CHECK: ldh %r0, [@bbbb+32]
define i16 @g_load16() nounwind {
%gep = getelementptr inbounds [128 x i16], [128 x i16]* @bbbb, i16 0, i16 16
%v = load i16, i16* %gep, align 2
ret i16 %v
}
; CHECK-LABEL: g_store8
; CHECK-NOT: add
; CHECK: stb %r0, [@cccc+16]
define void @g_store8(i8 %val) nounwind {
entry:
store i8 %val, i8* getelementptr inbounds ([128 x i8], [128 x i8]* @cccc, i8 0, i8 16), align 1
ret void
}
; CHECK-LABEL: g_load8
; CHECK-NOT: add
; CHECK: ldb %r0, [@cccc+16]
define i8 @g_load8() nounwind {
%gep = getelementptr inbounds [128 x i8], [128 x i8]* @cccc, i8 0, i8 16
%v = load i8, i8* %gep, align 1
ret i8 %v
}
; CHECK-LABEL: align2_load32
; CHECK-DAG: ldh %r[[REG0:[0-9]+]], [%r0,0]
; CHECK-DAG: ldh %r[[REG1:[0-9]+]], [%r0,2]
; CHECK-DAG: asl %r[[REG2:[0-9]+]], %r[[REG1]], 16
define i32 @align2_load32(i8* %p) nounwind {
entry:
%bp = bitcast i8* %p to i32*
%v = load i32, i32* %bp, align 2
ret i32 %v
}
; CHECK-LABEL: align1_load32
; CHECK-DAG: ldb %r[[REG0:[0-9]+]], [%r0,0]
; CHECK-DAG: ldb %r[[REG1:[0-9]+]], [%r0,1]
; CHECK-DAG: ldb %r[[REG2:[0-9]+]], [%r0,2]
; CHECK-DAG: ldb %r[[REG3:[0-9]+]], [%r0,3]
; CHECK-DAG: asl %r[[AREG1:[0-9]+]], %r[[REG1]], 8
; CHECK-DAG: asl %r[[AREG3:[0-9]+]], %r[[REG3]], 8
define i32 @align1_load32(i8* %p) nounwind {
entry:
%bp = bitcast i8* %p to i32*
%v = load i32, i32* %bp, align 1
ret i32 %v
}
; CHECK-LABEL: align1_load16
; CHECK-DAG: ldb %r[[REG0:[0-9]+]], [%r0,0]
; CHECK-DAG: ldb %r[[REG1:[0-9]+]], [%r0,1]
; CHECK-DAG: asl %r[[REG2:[0-9]+]], %r[[REG1]], 8
define i16 @align1_load16(i8* %p) nounwind {
entry:
%bp = bitcast i8* %p to i16*
%v = load i16, i16* %bp, align 1
ret i16 %v
}
; CHECK-LABEL: align2_store32
; CHECK-DAG: lsr %r[[REG:[0-9]+]], %r1, 16
; CHECK-DAG: sth %r1, [%r0,0]
; CHECK-DAG: sth %r[[REG:[0-9]+]], [%r0,2]
define void @align2_store32(i8* %p, i32 %v) nounwind {
entry:
%bp = bitcast i8* %p to i32*
store i32 %v, i32* %bp, align 2
ret void
}
; CHECK-LABEL: align1_store16
; CHECK-DAG: lsr %r[[REG:[0-9]+]], %r1, 8
; CHECK-DAG: stb %r1, [%r0,0]
; CHECK-DAG: stb %r[[REG:[0-9]+]], [%r0,1]
define void @align1_store16(i8* %p, i16 %v) nounwind {
entry:
%bp = bitcast i8* %p to i16*
store i16 %v, i16* %bp, align 1
ret void
}
; CHECK-LABEL: align1_store32
; CHECK-DAG: lsr %r[[REG0:[0-9]+]], %r1, 8
; CHECK-DAG: lsr %r[[REG1:[0-9]+]], %r1, 16
; CHECK-DAG: lsr %r[[REG2:[0-9]+]], %r1, 24
; CHECK-DAG: stb %r1, [%r0,0]
; CHECK-DAG: stb %r[[REG0]], [%r0,1]
; CHECK-DAG: stb %r[[REG1]], [%r0,2]
; CHECK-DAG: stb %r[[REG2]], [%r0,3]
define void @align1_store32(i8* %p, i32 %v) nounwind {
entry:
%bp = bitcast i8* %p to i32*
store i32 %v, i32* %bp, align 1
ret void
}

View File

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

View File

@ -0,0 +1,75 @@
# RUN: llvm-mc -triple=arc -disassemble %s | FileCheck %s
# CHECK: add %r0, %r0, %r0
0x00 0x20 0x00 0x00
# CHECK: add %r4, %r0, %r0
0x00 0x20 0x04 0x00
# CHECK: add %r2, %r0, %r3
0x00 0x20 0xc2 0x00
# CHECK: add %r2, %r0, %r4
0x00 0x20 0x02 0x01
# CHECK: add %r2, %r7, %r4
0x00 0x27 0x02 0x01
# CHECK: and %r2, %r7, %r4
0x04 0x27 0x02 0x01
# CHECK: and %r2, %r7, 4
0x44 0x27 0x02 0x01
# CHECK: and %r1, %r1, 255
0x84 0x21 0xc3 0x0f
# CHECK: asl %r1, %r1, 2
0x40 0x29 0x81 0x00
# CHECK: asl %r0, %r0, %r0
0x00 0x28 0x00 0x00
# CHECK: asr %r1, %r2, 31
0x42 0x2a 0xc1 0x07
# CHECK: asr %r1, %r3, 7
0x42 0x2b 0xc1 0x01
# CHECK: asr %r1, %r1, %r2
0x02 0x29 0x81 0x00
# CHECK: max %r0, %r2, %r1
0x08 0x22 0x40 0x00
# CHECK: max %r0, %r1, 15
0x48 0x21 0xc0 0x03
# CHECK: max %r0, %r2, 4000
0x08 0x22 0x80 0x0f 0x00 0x00 0xa0 0x0f
# CHECK: max %r2, %r2, 255
0x88 0x22 0xc3 0x0f
# CHECK: or %r18, %r16, 61440
0x05 0x20 0x92 0x2f 0x00 0x00 0x00 0xf0
# CHECK: or %r1, %r1, %r14
0x05 0x21 0x81 0x03
# CHECK: or %r1, %r14, %r1
0x05 0x26 0x41 0x10
# CHECK: or %r1, %r1, 128
0x85 0x21 0x02 0x00
# CHECK: sub %sp, %fp, 92
0x02 0x23 0x9c 0x3f 0x00 0x00 0x5c 0x00
# CHECK: sub %r2, %r7, %r4
0x02 0x27 0x02 0x01
# CHECK: sub %r0, %r22, %r0
0x02 0x26 0x00 0x20

View File

@ -0,0 +1,29 @@
# RUN: llvm-mc -triple=arc -disassemble %s | FileCheck %s
# CHECK: brlt %r2, 0, 60
0x3d 0x0a 0x12 0x00
# CHECK: brlo %r10, %r4, -112
0x91 0x0a 0x04 0x91
# CHECK: breq %r2, %r1, 44
0x2d 0x0a 0x40 0x00
# CHECK: brne %r0, 0, -16
0xf1 0x08 0x11 0x80
# CHECK: brhs %r2, %r8, 38
0x27 0x0a 0x05 0x02
# CHECK: bne 304
0x30 0x01 0x02 0x00
# CHECK: beq 268
0x0c 0x01 0x01 0x00
# CHECK: bhi 416
0xa0 0x01 0x0d 0x00
# CHECK: b -68
0xbd 0x07 0xcf 0xff

View File

@ -0,0 +1,47 @@
# RUN: llvm-mc -triple=arc -disassemble %s | FileCheck %s
# CHECK: ld %r0, [%r0,0]
0x00 0x10 0x00 0x00
# CHECK: ldh %r0, [%r0,0]
0x00 0x10 0x00 0x01
# CHECK: ldb %r0, [%r0,0]
0x00 0x10 0x80 0x00
# CHECK: ld %r1, [%r0,12]
0x0c 0x10 0x01 0x00
# CHECK: ld %r14, [%fp,-12]
0xf4 0x13 0x0e 0xb0
# CHECK: ld %r3, [%r0,-12]
0xf4 0x10 0x03 0x80
# CHECK: ld %r0, [%r0,244]
0xf4 0x10 0x00 0x00
# CHECK: ld %r0, [%r0,-12]
0xf4 0x10 0x00 0x80
# CHECK: ldh.x %r3, [%r1,0]
0x00 0x11 0x43 0x01
# CHECK: ldh.x %r2, [%r1,2]
0x02 0x11 0x42 0x01
# CHECK: ldh.x %r2, [%fp,-132]
0x7c 0x13 0x42 0xb1
# CHECK: ld %r0, [%r0,64000]
0x30 0x20 0x80 0x0f 0x00 0x00 0x00 0xfa
# CHECK: ld %r6, [63920]
0x00 0x16 0x06 0x70 0x00 0x00 0xb0 0xf9
# CHECK: stb %r2, [%sp,35]
0x23 0x1c 0x82 0x30
# CHECK: st %r7, [63920]
0x00 0x1e 0xc0 0x71 0x00 0x00 0xb0 0xf9

View File

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

View File

@ -0,0 +1,42 @@
# RUN: llvm-mc -triple=arc -disassemble %s | FileCheck %s
# CHECK: mov %r0, -1
0x8a 0x20 0xff 0x0f
# 32767 == 0x7fff
# CHECK: mov %r4, 32767
0x0a 0x24 0x80 0x0f 0x00 0x00 0xff 0x7f
# CHECK: mov.eq %r2, %r6
0xca 0x22 0x81 0x01
# CHECK: mov %r13, %r2
0x0a 0x25 0x80 0x10
# CHECK: mov %r1, 20
0x4a 0x21 0x00 0x05
# CHECK: st.aw %fp, [%sp,-4]
0xfc 0x1c 0xc8 0xb6
# CHECK: ld.ab %fp, [%sp,4]
0x04 0x14 0x1b 0x34
# CHECK: bl -2028
0x16 0x08 0xcf 0xff
# CHECK: cmp %r13, %r10
0x0c 0x25 0x80 0x92
# CHECK: cmp %r14, 0
0x4c 0x26 0x00 0x90
# CHECK: cmp %r23, 1
0x4c 0x27 0x40 0xa0
# CHECK: jl [%r21]
0x22 0x20 0x40 0x05
# CHECK: j [%r3]
0x20 0x20 0xc0 0x00