mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[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:
parent
94f045b3a9
commit
7fc741759e
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
33
lib/Target/ARC/ARC.h
Normal 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
25
lib/Target/ARC/ARC.td
Normal 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;
|
||||
}
|
83
lib/Target/ARC/ARCAsmPrinter.cpp
Normal file
83
lib/Target/ARC/ARCAsmPrinter.cpp
Normal 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());
|
||||
}
|
183
lib/Target/ARC/ARCBranchFinalize.cpp
Normal file
183
lib/Target/ARC/ARCBranchFinalize.cpp
Normal 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();
|
||||
}
|
41
lib/Target/ARC/ARCCallingConv.td
Normal file
41
lib/Target/ARC/ARCCallingConv.td
Normal 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)>;
|
103
lib/Target/ARC/ARCExpandPseudos.cpp
Normal file
103
lib/Target/ARC/ARCExpandPseudos.cpp
Normal 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();
|
||||
}
|
472
lib/Target/ARC/ARCFrameLowering.cpp
Normal file
472
lib/Target/ARC/ARCFrameLowering.cpp
Normal 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;
|
||||
}
|
78
lib/Target/ARC/ARCFrameLowering.h
Normal file
78
lib/Target/ARC/ARCFrameLowering.h
Normal 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
|
182
lib/Target/ARC/ARCISelDAGToDAG.cpp
Normal file
182
lib/Target/ARC/ARCISelDAGToDAG.cpp
Normal 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);
|
||||
}
|
767
lib/Target/ARC/ARCISelLowering.cpp
Normal file
767
lib/Target/ARC/ARCISelLowering.cpp
Normal 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");
|
||||
}
|
||||
}
|
121
lib/Target/ARC/ARCISelLowering.h
Normal file
121
lib/Target/ARC/ARCISelLowering.h
Normal 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
|
508
lib/Target/ARC/ARCInstrFormats.td
Normal file
508
lib/Target/ARC/ARCInstrFormats.td
Normal 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";
|
||||
}
|
||||
|
394
lib/Target/ARC/ARCInstrInfo.cpp
Normal file
394
lib/Target/ARC/ARCInstrInfo.cpp
Normal 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();
|
||||
}
|
94
lib/Target/ARC/ARCInstrInfo.h
Normal file
94
lib/Target/ARC/ARCInstrInfo.h
Normal 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
|
504
lib/Target/ARC/ARCInstrInfo.td
Normal file
504
lib/Target/ARC/ARCInstrInfo.td
Normal 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)>;
|
||||
|
115
lib/Target/ARC/ARCMCInstLower.cpp
Normal file
115
lib/Target/ARC/ARCMCInstLower.cpp
Normal 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);
|
||||
}
|
||||
}
|
44
lib/Target/ARC/ARCMCInstLower.h
Normal file
44
lib/Target/ARC/ARCMCInstLower.h
Normal 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
|
14
lib/Target/ARC/ARCMachineFunctionInfo.cpp
Normal file
14
lib/Target/ARC/ARCMachineFunctionInfo.cpp
Normal 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() {}
|
64
lib/Target/ARC/ARCMachineFunctionInfo.h
Normal file
64
lib/Target/ARC/ARCMachineFunctionInfo.h
Normal 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
|
233
lib/Target/ARC/ARCRegisterInfo.cpp
Normal file
233
lib/Target/ARC/ARCRegisterInfo.cpp
Normal 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;
|
||||
}
|
58
lib/Target/ARC/ARCRegisterInfo.h
Normal file
58
lib/Target/ARC/ARCRegisterInfo.h
Normal 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
|
80
lib/Target/ARC/ARCRegisterInfo.td
Normal file
80
lib/Target/ARC/ARCRegisterInfo.td
Normal 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)>;
|
||||
|
31
lib/Target/ARC/ARCSubtarget.cpp
Normal file
31
lib/Target/ARC/ARCSubtarget.cpp
Normal 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) {}
|
66
lib/Target/ARC/ARCSubtarget.h
Normal file
66
lib/Target/ARC/ARCSubtarget.h
Normal 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
|
95
lib/Target/ARC/ARCTargetMachine.cpp
Normal file
95
lib/Target/ARC/ARCTargetMachine.cpp
Normal 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));
|
||||
});
|
||||
}
|
51
lib/Target/ARC/ARCTargetMachine.h
Normal file
51
lib/Target/ARC/ARCTargetMachine.h
Normal 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
|
25
lib/Target/ARC/ARCTargetStreamer.h
Normal file
25
lib/Target/ARC/ARCTargetStreamer.h
Normal 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
|
55
lib/Target/ARC/ARCTargetTransformInfo.h
Normal file
55
lib/Target/ARC/ARCTargetTransformInfo.h
Normal 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
|
30
lib/Target/ARC/CMakeLists.txt
Normal file
30
lib/Target/ARC/CMakeLists.txt
Normal 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)
|
298
lib/Target/ARC/Disassembler/ARCDisassembler.cpp
Normal file
298
lib/Target/ARC/Disassembler/ARCDisassembler.cpp
Normal 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);
|
||||
}
|
3
lib/Target/ARC/Disassembler/CMakeLists.txt
Normal file
3
lib/Target/ARC/Disassembler/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
add_llvm_library(LLVMARCDisassembler
|
||||
ARCDisassembler.cpp
|
||||
)
|
23
lib/Target/ARC/Disassembler/LLVMBuild.txt
Normal file
23
lib/Target/ARC/Disassembler/LLVMBuild.txt
Normal 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
|
166
lib/Target/ARC/InstPrinter/ARCInstPrinter.cpp
Normal file
166
lib/Target/ARC/InstPrinter/ARCInstPrinter.cpp
Normal 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());
|
||||
}
|
46
lib/Target/ARC/InstPrinter/ARCInstPrinter.h
Normal file
46
lib/Target/ARC/InstPrinter/ARCInstPrinter.h
Normal 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
|
3
lib/Target/ARC/InstPrinter/CMakeLists.txt
Normal file
3
lib/Target/ARC/InstPrinter/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
add_llvm_library(LLVMARCAsmPrinter
|
||||
ARCInstPrinter.cpp
|
||||
)
|
23
lib/Target/ARC/InstPrinter/LLVMBuild.txt
Normal file
23
lib/Target/ARC/InstPrinter/LLVMBuild.txt
Normal 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
|
45
lib/Target/ARC/LLVMBuild.txt
Normal file
45
lib/Target/ARC/LLVMBuild.txt
Normal 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
|
57
lib/Target/ARC/MCTargetDesc/ARCInfo.h
Normal file
57
lib/Target/ARC/MCTargetDesc/ARCInfo.h
Normal 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
|
32
lib/Target/ARC/MCTargetDesc/ARCMCAsmInfo.cpp
Normal file
32
lib/Target/ARC/MCTargetDesc/ARCMCAsmInfo.cpp
Normal 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;
|
||||
}
|
32
lib/Target/ARC/MCTargetDesc/ARCMCAsmInfo.h
Normal file
32
lib/Target/ARC/MCTargetDesc/ARCMCAsmInfo.h
Normal 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
|
103
lib/Target/ARC/MCTargetDesc/ARCMCTargetDesc.cpp
Normal file
103
lib/Target/ARC/MCTargetDesc/ARCMCTargetDesc.cpp
Normal 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);
|
||||
}
|
39
lib/Target/ARC/MCTargetDesc/ARCMCTargetDesc.h
Normal file
39
lib/Target/ARC/MCTargetDesc/ARCMCTargetDesc.h
Normal 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
|
4
lib/Target/ARC/MCTargetDesc/CMakeLists.txt
Normal file
4
lib/Target/ARC/MCTargetDesc/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
add_llvm_library(LLVMARCDesc
|
||||
ARCMCTargetDesc.cpp
|
||||
ARCMCAsmInfo.cpp
|
||||
)
|
23
lib/Target/ARC/MCTargetDesc/LLVMBuild.txt
Normal file
23
lib/Target/ARC/MCTargetDesc/LLVMBuild.txt
Normal 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
|
22
lib/Target/ARC/TargetInfo/ARCTargetInfo.cpp
Normal file
22
lib/Target/ARC/TargetInfo/ARCTargetInfo.cpp
Normal 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");
|
||||
}
|
3
lib/Target/ARC/TargetInfo/CMakeLists.txt
Normal file
3
lib/Target/ARC/TargetInfo/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
add_llvm_library(LLVMARCInfo
|
||||
ARCTargetInfo.cpp
|
||||
)
|
23
lib/Target/ARC/TargetInfo/LLVMBuild.txt
Normal file
23
lib/Target/ARC/TargetInfo/LLVMBuild.txt
Normal 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
|
@ -20,6 +20,7 @@
|
||||
[common]
|
||||
subdirectories =
|
||||
AMDGPU
|
||||
ARC
|
||||
ARM
|
||||
AArch64
|
||||
AVR
|
||||
|
255
test/CodeGen/ARC/alu.ll
Normal file
255
test/CodeGen/ARC/alu.ll
Normal 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
37
test/CodeGen/ARC/brcc.ll
Normal 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
88
test/CodeGen/ARC/call.ll
Normal 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
272
test/CodeGen/ARC/ldst.ll
Normal 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
|
||||
}
|
3
test/CodeGen/ARC/lit.local.cfg
Normal file
3
test/CodeGen/ARC/lit.local.cfg
Normal file
@ -0,0 +1,3 @@
|
||||
if not 'ARC' in config.root.targets:
|
||||
config.unsupported = True
|
||||
|
75
test/MC/Disassembler/ARC/alu.txt
Normal file
75
test/MC/Disassembler/ARC/alu.txt
Normal 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
|
||||
|
||||
|
29
test/MC/Disassembler/ARC/br.txt
Normal file
29
test/MC/Disassembler/ARC/br.txt
Normal 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
|
||||
|
47
test/MC/Disassembler/ARC/ldst.txt
Normal file
47
test/MC/Disassembler/ARC/ldst.txt
Normal 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
|
||||
|
3
test/MC/Disassembler/ARC/lit.local.cfg
Normal file
3
test/MC/Disassembler/ARC/lit.local.cfg
Normal file
@ -0,0 +1,3 @@
|
||||
if not 'ARC' in config.root.targets:
|
||||
config.unsupported = True
|
||||
|
42
test/MC/Disassembler/ARC/misc.txt
Normal file
42
test/MC/Disassembler/ARC/misc.txt
Normal 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
|
||||
|
Loading…
Reference in New Issue
Block a user