1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[Hexagon] Disassembling, printing, and emitting instructions a whole-bundle at a time which is the semantic unit for Hexagon. Fixing tests to use the new format. Disabling tests in the direct object emission path for a followup patch.

llvm-svn: 238556
This commit is contained in:
Colin LeMahieu 2015-05-29 14:44:13 +00:00
parent 2ea0919069
commit 084c4d499d
23 changed files with 504 additions and 180 deletions

View File

@ -7,9 +7,11 @@
//
//===----------------------------------------------------------------------===//
#include "Hexagon.h"
#include "MCTargetDesc/HexagonBaseInfo.h"
#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "MCTargetDesc/HexagonMCTargetDesc.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
#include "llvm/MC/MCExpr.h"
@ -27,6 +29,7 @@
#include <vector>
using namespace llvm;
using namespace Hexagon;
#define DEBUG_TYPE "hexagon-disassembler"
@ -37,9 +40,14 @@ namespace {
/// \brief Hexagon disassembler for all Hexagon platforms.
class HexagonDisassembler : public MCDisassembler {
public:
std::unique_ptr<MCInst *> CurrentBundle;
HexagonDisassembler(MCSubtargetInfo const &STI, MCContext &Ctx)
: MCDisassembler(STI, Ctx) {}
: MCDisassembler(STI, Ctx), CurrentBundle(new MCInst *) {}
DecodeStatus getSingleInstruction(MCInst &Instr, MCInst &MCB,
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &VStream, raw_ostream &CStream,
bool &Complete) const;
DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &VStream,
@ -191,17 +199,53 @@ DecodeStatus HexagonDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
uint64_t Address,
raw_ostream &os,
raw_ostream &cs) const {
Size = 4;
if (Bytes.size() < 4)
return MCDisassembler::Fail;
DecodeStatus Result = DecodeStatus::Success;
bool Complete = false;
Size = 0;
uint32_t insn =
*CurrentBundle = &MI;
MI.setOpcode(Hexagon::BUNDLE);
MI.addOperand(MCOperand::createImm(0));
while (Result == Success && Complete == false)
{
if (Bytes.size() < HEXAGON_INSTR_SIZE)
return MCDisassembler::Fail;
MCInst * Inst = new (getContext()) MCInst;
Result = getSingleInstruction(*Inst, MI, Bytes, Address, os, cs, Complete);
MI.addOperand(MCOperand::createInst(Inst));
Size += HEXAGON_INSTR_SIZE;
Bytes = Bytes.slice(HEXAGON_INSTR_SIZE);
}
return Result;
}
DecodeStatus HexagonDisassembler::getSingleInstruction(
MCInst &MI, MCInst &MCB, ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &os, raw_ostream &cs, bool &Complete) const {
assert(Bytes.size() >= HEXAGON_INSTR_SIZE);
uint32_t Instruction =
llvm::support::endian::read<uint32_t, llvm::support::little,
llvm::support::unaligned>(Bytes.data());
// Remove parse bits.
insn &= ~static_cast<uint32_t>(HexagonII::InstParseBits::INST_PARSE_MASK);
DecodeStatus Result = decodeInstruction(DecoderTable32, MI, insn, Address, this, STI);
HexagonMCInstrInfo::AppendImplicitOperands(MI);
auto BundleSize = HexagonMCInstrInfo::bundleSize(MCB);
if ((Instruction & HexagonII::INST_PARSE_MASK) ==
HexagonII::INST_PARSE_LOOP_END) {
if (BundleSize == 0)
HexagonMCInstrInfo::setInnerLoop(MCB);
else if (BundleSize == 1)
HexagonMCInstrInfo::setOuterLoop(MCB);
else
return DecodeStatus::Fail;
}
DecodeStatus Result = DecodeStatus::Success;
if ((Instruction & HexagonII::INST_PARSE_MASK) ==
HexagonII::INST_PARSE_PACKET_END)
Complete = true;
// Calling the auto-generated decoder function.
Result =
decodeInstruction(DecoderTable32, MI, Instruction, Address, this, STI);
return Result;
}

View File

@ -76,4 +76,8 @@ namespace llvm {
// Maximum number of words and instructions in a packet.
#define HEXAGON_PACKET_SIZE 4
// Minimum number of instructions in an end-loop packet.
#define HEXAGON_PACKET_INNER_SIZE 2
#define HEXAGON_PACKET_OUTER_SIZE 3
#endif

View File

@ -177,47 +177,29 @@ bool HexagonAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
/// the current output stream.
///
void HexagonAsmPrinter::EmitInstruction(const MachineInstr *MI) {
MCInst MCB;
MCB.setOpcode(Hexagon::BUNDLE);
MCB.addOperand(MCOperand::createImm(0));
if (MI->isBundle()) {
std::vector<MachineInstr const *> BundleMIs;
const MachineBasicBlock *MBB = MI->getParent();
const MachineBasicBlock* MBB = MI->getParent();
MachineBasicBlock::const_instr_iterator MII = MI;
++MII;
unsigned int IgnoreCount = 0;
while (MII != MBB->end() && MII->isInsideBundle()) {
const MachineInstr *MInst = MII;
if (MInst->getOpcode() == TargetOpcode::DBG_VALUE ||
MInst->getOpcode() == TargetOpcode::IMPLICIT_DEF) {
IgnoreCount++;
++MII;
continue;
}
// BundleMIs.push_back(&*MII);
BundleMIs.push_back(MInst);
++MII;
}
unsigned Size = BundleMIs.size();
assert((Size + IgnoreCount) == MI->getBundleSize() && "Corrupt Bundle!");
for (unsigned Index = 0; Index < Size; Index++) {
MCInst MCI;
unsigned IgnoreCount = 0;
HexagonLowerToMC(BundleMIs[Index], MCI, *this);
HexagonMCInstrInfo::AppendImplicitOperands(MCI);
HexagonMCInstrInfo::setPacketBegin(MCI, Index == 0);
HexagonMCInstrInfo::setPacketEnd(MCI, Index == (Size - 1));
EmitToStreamer(*OutStreamer, MCI);
for (++MII; MII != MBB->end() && MII->isInsideBundle(); ++MII) {
if (MII->getOpcode() == TargetOpcode::DBG_VALUE ||
MII->getOpcode() == TargetOpcode::IMPLICIT_DEF)
++IgnoreCount;
else {
HexagonLowerToMC(MII, MCB, *this);
}
}
}
else {
MCInst MCI;
HexagonLowerToMC(MI, MCI, *this);
HexagonMCInstrInfo::AppendImplicitOperands(MCI);
if (MI->getOpcode() == Hexagon::ENDLOOP0) {
HexagonMCInstrInfo::setPacketBegin(MCI, true);
HexagonMCInstrInfo::setPacketEnd(MCI, true);
}
EmitToStreamer(*OutStreamer, MCI);
HexagonLowerToMC(MI, MCB, *this);
HexagonMCInstrInfo::padEndloop(MCB);
}
EmitToStreamer(*OutStreamer, MCB);
return;
}

View File

@ -66,10 +66,8 @@ def DoubleWordAccess : MemAccessSize<4>;// Double word access instruction (memd)
class OpcodeHexagon {
field bits<32> Inst = ?; // Default to an invalid insn.
bits<4> IClass = 0; // ICLASS
bits<2> IParse = 0; // Parse bits.
let Inst{31-28} = IClass;
let Inst{15-14} = IParse;
bits<1> zero = 0;
}

View File

@ -15,9 +15,12 @@
#include "Hexagon.h"
#include "HexagonAsmPrinter.h"
#include "HexagonMachineFunctionInfo.h"
#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Mangler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
@ -38,9 +41,20 @@ static MCOperand GetSymbolRef(const MachineOperand& MO, const MCSymbol* Symbol,
}
// Create an MCInst from a MachineInstr
void llvm::HexagonLowerToMC(MachineInstr const* MI, MCInst& MCI,
void llvm::HexagonLowerToMC(MachineInstr const* MI, MCInst& MCB,
HexagonAsmPrinter& AP) {
MCI.setOpcode(MI->getOpcode());
if(MI->getOpcode() == Hexagon::ENDLOOP0){
HexagonMCInstrInfo::setInnerLoop(MCB);
return;
}
if(MI->getOpcode() == Hexagon::ENDLOOP1){
HexagonMCInstrInfo::setOuterLoop(MCB);
return;
}
MCInst* MCI = new (AP.OutContext) MCInst;
MCI->setOpcode(MI->getOpcode());
assert(MCI->getOpcode() == static_cast<unsigned>(MI->getOpcode()) &&
"MCI opcode should have been set on construction");
for (unsigned i = 0, e = MI->getNumOperands(); i < e; i++) {
const MachineOperand &MO = MI->getOperand(i);
@ -88,6 +102,7 @@ void llvm::HexagonLowerToMC(MachineInstr const* MI, MCInst& MCI,
break;
}
MCI.addOperand(MCO);
MCI->addOperand(MCO);
}
MCB.addOperand(MCOperand::createInst(MCI));
}

View File

@ -190,7 +190,7 @@ namespace HexagonII {
MO_GPREL
};
enum class InstParseBits : uint32_t {
enum InstParseBits {
INST_PARSE_MASK = 0x0000c000,
INST_PARSE_PACKET_END = 0x0000c000,
INST_PARSE_LOOP_END = 0x00008000,

View File

@ -28,7 +28,47 @@ using namespace llvm;
#define GET_INSTRUCTION_NAME
#include "HexagonGenAsmWriter.inc"
const char HexagonInstPrinter::PacketPadding = '\t';
HexagonAsmInstPrinter::HexagonAsmInstPrinter(MCInstPrinter *RawPrinter)
: MCInstPrinter(*RawPrinter), RawPrinter(RawPrinter) {}
void HexagonAsmInstPrinter::printInst(MCInst const *MI, raw_ostream &O,
StringRef Annot,
MCSubtargetInfo const &STI) {
assert(HexagonMCInstrInfo::isBundle(*MI));
assert(HexagonMCInstrInfo::bundleSize(*MI) <= HEXAGON_PACKET_SIZE);
std::string Buffer;
{
raw_string_ostream TempStream(Buffer);
RawPrinter->printInst(MI, TempStream, "", STI);
}
StringRef Contents(Buffer);
auto PacketBundle = Contents.rsplit('\n');
auto HeadTail = PacketBundle.first.split('\n');
auto Preamble = "\t{\n\t\t";
auto Separator = "";
while(!HeadTail.first.empty()) {
O << Separator;
StringRef Inst;
auto Duplex = HeadTail.first.split('\v');
if(!Duplex.second.empty()){
O << Duplex.first << "\n";
Inst = Duplex.second;
}
else
Inst = Duplex.first;
O << Preamble;
O << Inst;
HeadTail = HeadTail.second.split('\n');
Preamble = "";
Separator = "\n\t\t";
}
O << "\n\t}" << PacketBundle.second;
}
void HexagonAsmInstPrinter::printRegName(raw_ostream &O, unsigned RegNo) const {
RawPrinter->printRegName(O, RegNo);
}
// Return the minimum value that a constant extendable operand can have
// without being extended.
static int getMinValue(uint64_t TSFlags) {
@ -77,48 +117,38 @@ void HexagonInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
OS << getRegisterName(RegNo);
}
void HexagonInstPrinter::printInst(MCInst const *MI, raw_ostream &O,
void HexagonInstPrinter::setExtender(MCInst const &MCI) {
HasExtender = HexagonMCInstrInfo::isImmext(MCI);
}
void HexagonInstPrinter::printInst(MCInst const *MI, raw_ostream &OS,
StringRef Annot,
const MCSubtargetInfo &STI) {
const char startPacket = '{',
endPacket = '}';
// TODO: add outer HW loop when it's supported too.
if (MI->getOpcode() == Hexagon::ENDLOOP0) {
// Ending a harware loop is different from ending an regular packet.
assert(HexagonMCInstrInfo::isPacketEnd(*MI) && "Loop-end must also end the packet");
if (HexagonMCInstrInfo::isPacketBegin(*MI)) {
// There must be a packet to end a loop.
// FIXME: when shuffling is always run, this shouldn't be needed.
MCInst Nop;
StringRef NoAnnot;
Nop.setOpcode (Hexagon::A2_nop);
HexagonMCInstrInfo::setPacketBegin (Nop, HexagonMCInstrInfo::isPacketBegin(*MI));
printInst (&Nop, O, NoAnnot, STI);
}
// Close the packet.
if (HexagonMCInstrInfo::isPacketEnd(*MI))
O << PacketPadding << endPacket;
printInstruction(MI, O);
}
else {
// Prefix the insn opening the packet.
if (HexagonMCInstrInfo::isPacketBegin(*MI))
O << PacketPadding << startPacket << '\n';
printInstruction(MI, O);
// Suffix the insn closing the packet.
if (HexagonMCInstrInfo::isPacketEnd(*MI))
// Suffix the packet in a new line always, since the GNU assembler has
// issues with a closing brace on the same line as CONST{32,64}.
O << '\n' << PacketPadding << endPacket;
MCSubtargetInfo const &STI) {
assert(HexagonMCInstrInfo::isBundle(*MI));
assert(HexagonMCInstrInfo::bundleSize(*MI) <= HEXAGON_PACKET_SIZE);
HasExtender = false;
for (auto const &I : HexagonMCInstrInfo::bundleInstructions(*MI)) {
MCInst const &MCI = *I.getInst();
printInstruction(&MCI, OS);
setExtender(MCI);
OS << "\n";
}
printAnnotation(O, Annot);
auto Separator = "";
if (HexagonMCInstrInfo::isInnerLoop(*MI)) {
OS << Separator;
Separator = " ";
MCInst ME;
ME.setOpcode(Hexagon::ENDLOOP0);
printInstruction(&ME, OS);
}
if (HexagonMCInstrInfo::isOuterLoop(*MI)) {
OS << Separator;
Separator = " ";
MCInst ME;
ME.setOpcode(Hexagon::ENDLOOP1);
printInstruction(&ME, OS);
}
}
void HexagonInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,

View File

@ -18,6 +18,21 @@
#include "llvm/MC/MCInstrInfo.h"
namespace llvm {
class HexagonAsmInstPrinter : public MCInstPrinter {
public:
HexagonAsmInstPrinter(MCInstPrinter *RawPrinter);
void printInst(MCInst const *MI, raw_ostream &O, StringRef Annot,
MCSubtargetInfo const &STI) override;
void printRegName(raw_ostream &O, unsigned RegNo) const override;
std::unique_ptr<MCInstPrinter> RawPrinter;
};
/// Prints bundles as a newline separated list of individual instructions
/// Duplexes are separated by a vertical tab \v character
/// A trailing line includes bundle properties such as endloop0/1
///
/// r0 = add(r1, r2)
/// r0 = #0 \v jump 0x0
/// :endloop0 :endloop1
class HexagonInstPrinter : public MCInstPrinter {
public:
explicit HexagonInstPrinter(MCAsmInfo const &MAI,
@ -74,11 +89,11 @@ namespace llvm {
void printSymbol(const MCInst *MI, unsigned OpNo, raw_ostream &O, bool hi)
const;
static const char PacketPadding;
private:
const MCInstrInfo &MII;
bool HasExtender;
void setExtender(MCInst const &MCI);
};
} // end namespace llvm

View File

@ -32,16 +32,6 @@ using namespace Hexagon;
STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
namespace {
/// \brief 10.6 Instruction Packets
/// Possible values for instruction packet parse field.
enum class ParseField { duplex = 0x0, last0 = 0x1, last1 = 0x2, end = 0x3 };
/// \brief Returns the packet bits based on instruction position.
uint32_t getPacketBits(MCInst const &HMI) {
unsigned const ParseFieldOffset = 14;
ParseField Field = HexagonMCInstrInfo::isPacketEnd(HMI) ? ParseField::end
: ParseField::last0;
return static_cast<uint32_t>(Field) << ParseFieldOffset;
}
void emitLittleEndian(uint64_t Binary, raw_ostream &OS) {
OS << static_cast<uint8_t>((Binary >> 0x00) & 0xff);
OS << static_cast<uint8_t>((Binary >> 0x08) & 0xff);
@ -53,15 +43,120 @@ void emitLittleEndian(uint64_t Binary, raw_ostream &OS) {
HexagonMCCodeEmitter::HexagonMCCodeEmitter(MCInstrInfo const &aMII,
MCContext &aMCT)
: MCT(aMCT), MCII(aMII), Addend(new unsigned(0)),
Extended(new bool(false)) {}
Extended(new bool(false)), CurrentBundle(new MCInst const *) {}
uint32_t HexagonMCCodeEmitter::parseBits(size_t Instruction, size_t Last,
MCInst const &MCB,
MCInst const &MCI) const {
if (Instruction == 0) {
if (HexagonMCInstrInfo::isInnerLoop(MCB)) {
assert(Instruction != Last);
return HexagonII::INST_PARSE_LOOP_END;
}
}
if (Instruction == 1) {
if (HexagonMCInstrInfo::isOuterLoop(MCB)) {
assert(Instruction != Last);
return HexagonII::INST_PARSE_LOOP_END;
}
}
if(Instruction == Last)
return HexagonII::INST_PARSE_PACKET_END;
return HexagonII::INST_PARSE_NOT_END;
}
void HexagonMCCodeEmitter::encodeInstruction(MCInst const &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
MCSubtargetInfo const &STI) const {
uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI) | getPacketBits(MI);
assert(HexagonMCInstrInfo::getDesc(MCII, MI).getSize() == 4 &&
"All instructions should be 32bit");
(void)&MCII;
MCInst &HMB = const_cast<MCInst &>(MI);
assert(HexagonMCInstrInfo::isBundle(HMB));
DEBUG(dbgs() << "Encoding bundle\n";);
*Addend = 0;
*Extended = false;
*CurrentBundle = &MI;
size_t Instruction = 0;
size_t Last = HexagonMCInstrInfo::bundleSize(HMB) - 1;
for (auto &I : HexagonMCInstrInfo::bundleInstructions(HMB)) {
MCInst &HMI = const_cast<MCInst &>(*I.getInst());
EncodeSingleInstruction(HMI, OS, Fixups, STI,
parseBits(Instruction, Last, HMB, HMI),
Instruction);
*Extended = HexagonMCInstrInfo::isImmext(HMI);
*Addend += HEXAGON_INSTR_SIZE;
++Instruction;
}
return;
}
/// EncodeSingleInstruction - Emit a single
void HexagonMCCodeEmitter::EncodeSingleInstruction(
const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI, uint32_t Parse, size_t Index) const {
MCInst HMB = MI;
assert(!HexagonMCInstrInfo::isBundle(HMB));
uint64_t Binary;
// Pseudo instructions don't get encoded and shouldn't be here
// in the first place!
assert(!HexagonMCInstrInfo::getDesc(MCII, HMB).isPseudo() &&
"pseudo-instruction found");
DEBUG(dbgs() << "Encoding insn"
" `" << HexagonMCInstrInfo::getName(MCII, HMB) << "'"
"\n");
if (HexagonMCInstrInfo::isNewValue(MCII, HMB)) {
// Calculate the new value distance to the associated producer
MCOperand &MCO =
HMB.getOperand(HexagonMCInstrInfo::getNewValueOp(MCII, HMB));
unsigned SOffset = 0;
unsigned Register = MCO.getReg();
unsigned Register1;
auto Instructions = HexagonMCInstrInfo::bundleInstructions(**CurrentBundle);
auto i = Instructions.begin() + Index - 1;
for (;; --i) {
assert(i != Instructions.begin() - 1 && "Couldn't find producer");
MCInst const &Inst = *i->getInst();
if (HexagonMCInstrInfo::isImmext(Inst))
continue;
++SOffset;
Register1 =
HexagonMCInstrInfo::hasNewValue(MCII, Inst)
? HexagonMCInstrInfo::getNewValueOperand(MCII, Inst).getReg()
: static_cast<unsigned>(Hexagon::NoRegister);
if (Register != Register1)
// This isn't the register we're looking for
continue;
if (!HexagonMCInstrInfo::isPredicated(MCII, Inst))
// Producer is unpredicated
break;
assert(HexagonMCInstrInfo::isPredicated(MCII, HMB) &&
"Unpredicated consumer depending on predicated producer");
if (HexagonMCInstrInfo::isPredicatedTrue(MCII, Inst) ==
HexagonMCInstrInfo::isPredicatedTrue(MCII, HMB))
// Producer predicate sense matched ours
break;
}
// Hexagon PRM 10.11 Construct Nt from distance
unsigned Offset = SOffset;
Offset <<= 1;
MCO.setReg(Offset + Hexagon::R0);
}
Binary = getBinaryCodeForInstr(HMB, Fixups, STI);
// Check for unimplemented instructions. Immediate extenders
// are encoded as zero, so they need to be accounted for.
if ((!Binary) &&
((HMB.getOpcode() != DuplexIClass0) && (HMB.getOpcode() != A4_ext) &&
(HMB.getOpcode() != A4_ext_b) && (HMB.getOpcode() != A4_ext_c) &&
(HMB.getOpcode() != A4_ext_g))) {
// Use a A2_nop for unimplemented instructions.
DEBUG(dbgs() << "Unimplemented inst: "
" `" << HexagonMCInstrInfo::getName(MCII, HMB) << "'"
"\n");
llvm_unreachable("Unimplemented Instruction");
}
Binary |= Parse;
emitLittleEndian(Binary, OS);
++MCNumEmitted;
}

View File

@ -30,6 +30,7 @@ class HexagonMCCodeEmitter : public MCCodeEmitter {
MCInstrInfo const &MCII;
std::unique_ptr<unsigned> Addend;
std::unique_ptr<bool> Extended;
std::unique_ptr<MCInst const *> CurrentBundle;
// helper routine for getMachineOpValue()
unsigned getExprOpValue(const MCInst &MI, const MCOperand &MO,
@ -39,12 +40,21 @@ class HexagonMCCodeEmitter : public MCCodeEmitter {
public:
HexagonMCCodeEmitter(MCInstrInfo const &aMII, MCContext &aMCT);
// Return parse bits for instruction `MCI' inside bundle `MCB'
uint32_t parseBits(size_t Instruction, size_t Last, MCInst const &MCB,
MCInst const &MCI) const;
MCSubtargetInfo const &getSubtargetInfo() const;
void encodeInstruction(MCInst const &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
MCSubtargetInfo const &STI) const override;
void EncodeSingleInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI,
uint32_t Parse, size_t Index) const;
// \brief TableGen'erated function for getting the
// binary encoding for an instruction.
uint64_t getBinaryCodeForInstr(MCInst const &MI,

View File

@ -11,13 +11,23 @@
//
//===----------------------------------------------------------------------===//
#include "HexagonMCInstrInfo.h"
#include "Hexagon.h"
#include "HexagonBaseInfo.h"
#include "HexagonMCInstrInfo.h"
namespace llvm {
void HexagonMCInstrInfo::AppendImplicitOperands(MCInst &MCI) {
MCI.addOperand(MCOperand::createImm(0));
MCI.addOperand(MCOperand::createInst(nullptr));
iterator_range<MCInst::const_iterator>
HexagonMCInstrInfo::bundleInstructions(MCInst const &MCI) {
assert(isBundle(MCI));
return iterator_range<MCInst::const_iterator>(
MCI.begin() + bundleInstructionsOffset, MCI.end());
}
size_t HexagonMCInstrInfo::bundleSize(MCInst const &MCI) {
if (HexagonMCInstrInfo::isBundle(MCI))
return (MCI.size() - bundleInstructionsOffset);
else
return (1);
}
HexagonII::MemAccessSize
@ -58,12 +68,6 @@ unsigned HexagonMCInstrInfo::getExtentBits(MCInstrInfo const &MCII,
return ((F >> HexagonII::ExtentBitsPos) & HexagonII::ExtentBitsMask);
}
std::bitset<16> HexagonMCInstrInfo::GetImplicitBits(MCInst const &MCI) {
SanityCheckImplicitOperands(MCI);
std::bitset<16> Bits(MCI.getOperand(MCI.getNumOperands() - 2).getImm());
return Bits;
}
// Return the max value that a constant extendable operand can have
// without being extended.
int HexagonMCInstrInfo::getMaxValue(MCInstrInfo const &MCII,
@ -99,9 +103,14 @@ char const *HexagonMCInstrInfo::getName(MCInstrInfo const &MCII,
return MCII.getName(MCI.getOpcode());
}
// Return the operand that consumes or produces a new value.
MCOperand const &HexagonMCInstrInfo::getNewValue(MCInstrInfo const &MCII,
unsigned short HexagonMCInstrInfo::getNewValueOp(MCInstrInfo const &MCII,
MCInst const &MCI) {
const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
return ((F >> HexagonII::NewValueOpPos) & HexagonII::NewValueOpMask);
}
MCOperand const &HexagonMCInstrInfo::getNewValueOperand(MCInstrInfo const &MCII,
MCInst const &MCI) {
uint64_t const F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
unsigned const O =
(F >> HexagonII::NewValueOpPos) & HexagonII::NewValueOpMask;
@ -128,6 +137,12 @@ bool HexagonMCInstrInfo::hasNewValue(MCInstrInfo const &MCII,
return ((F >> HexagonII::hasNewValuePos) & HexagonII::hasNewValueMask);
}
bool HexagonMCInstrInfo::isBundle(MCInst const &MCI) {
auto Result = Hexagon::BUNDLE == MCI.getOpcode();
assert(!Result || (MCI.size() > 0 && MCI.getOperand(0).isImm()));
return Result;
}
// Return whether the insn is an actual insn.
bool HexagonMCInstrInfo::isCanon(MCInstrInfo const &MCII, MCInst const &MCI) {
return (!HexagonMCInstrInfo::getDesc(MCII, MCI).isPseudo() &&
@ -187,6 +202,18 @@ bool HexagonMCInstrInfo::isExtended(MCInstrInfo const &MCII,
return (F >> HexagonII::ExtendedPos) & HexagonII::ExtendedMask;
}
bool HexagonMCInstrInfo::isImmext(MCInst const &MCI) {
auto Op = MCI.getOpcode();
return (Op == Hexagon::A4_ext_b || Op == Hexagon::A4_ext_c ||
Op == Hexagon::A4_ext_g || Op == Hexagon::A4_ext);
}
bool HexagonMCInstrInfo::isInnerLoop(MCInst const &MCI) {
assert(isBundle(MCI));
int64_t Flags = MCI.getOperand(0).getImm();
return (Flags & innerLoopMask) != 0;
}
// Return whether the insn is a new-value consumer.
bool HexagonMCInstrInfo::isNewValue(MCInstrInfo const &MCII,
MCInst const &MCI) {
@ -203,14 +230,23 @@ bool HexagonMCInstrInfo::isOperandExtended(MCInstrInfo const &MCII,
OperandNum;
}
bool HexagonMCInstrInfo::isPacketBegin(MCInst const &MCI) {
std::bitset<16> Bits(GetImplicitBits(MCI));
return Bits.test(packetBeginIndex);
bool HexagonMCInstrInfo::isOuterLoop(MCInst const &MCI) {
assert(isBundle(MCI));
int64_t Flags = MCI.getOperand(0).getImm();
return (Flags & outerLoopMask) != 0;
}
bool HexagonMCInstrInfo::isPacketEnd(MCInst const &MCI) {
std::bitset<16> Bits(GetImplicitBits(MCI));
return Bits.test(packetEndIndex);
bool HexagonMCInstrInfo::isPredicated(MCInstrInfo const &MCII,
MCInst const &MCI) {
const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
return ((F >> HexagonII::PredicatedPos) & HexagonII::PredicatedMask);
}
bool HexagonMCInstrInfo::isPredicatedTrue(MCInstrInfo const &MCII,
MCInst const &MCI) {
const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags;
return (
!((F >> HexagonII::PredicatedFalsePos) & HexagonII::PredicatedFalseMask));
}
// Return whether the insn is a prefix.
@ -224,25 +260,26 @@ bool HexagonMCInstrInfo::isSolo(MCInstrInfo const &MCII, MCInst const &MCI) {
return ((F >> HexagonII::SoloPos) & HexagonII::SoloMask);
}
void HexagonMCInstrInfo::resetPacket(MCInst &MCI) {
setPacketBegin(MCI, false);
setPacketEnd(MCI, false);
void HexagonMCInstrInfo::padEndloop(MCInst &MCB) {
MCInst Nop;
Nop.setOpcode(Hexagon::A2_nop);
assert(isBundle(MCB));
while ((HexagonMCInstrInfo::isInnerLoop(MCB) &&
(HexagonMCInstrInfo::bundleSize(MCB) < HEXAGON_PACKET_INNER_SIZE)) ||
((HexagonMCInstrInfo::isOuterLoop(MCB) &&
(HexagonMCInstrInfo::bundleSize(MCB) < HEXAGON_PACKET_OUTER_SIZE))))
MCB.addOperand(MCOperand::createInst(new MCInst(Nop)));
}
void HexagonMCInstrInfo::SetImplicitBits(MCInst &MCI, std::bitset<16> Bits) {
SanityCheckImplicitOperands(MCI);
MCI.getOperand(MCI.getNumOperands() - 2).setImm(Bits.to_ulong());
void HexagonMCInstrInfo::setInnerLoop(MCInst &MCI) {
assert(isBundle(MCI));
MCOperand &Operand = MCI.getOperand(0);
Operand.setImm(Operand.getImm() | innerLoopMask);
}
void HexagonMCInstrInfo::setPacketBegin(MCInst &MCI, bool f) {
std::bitset<16> Bits(GetImplicitBits(MCI));
Bits.set(packetBeginIndex, f);
SetImplicitBits(MCI, Bits);
}
void HexagonMCInstrInfo::setPacketEnd(MCInst &MCI, bool f) {
std::bitset<16> Bits(GetImplicitBits(MCI));
Bits.set(packetEndIndex, f);
SetImplicitBits(MCI, Bits);
void HexagonMCInstrInfo::setOuterLoop(MCInst &MCI) {
assert(isBundle(MCI));
MCOperand &Operand = MCI.getOperand(0);
Operand.setImm(Operand.getImm() | outerLoopMask);
}
}

View File

@ -28,7 +28,19 @@ namespace HexagonII {
enum class MemAccessSize;
}
namespace HexagonMCInstrInfo {
void AppendImplicitOperands(MCInst &MCI);
size_t const innerLoopOffset = 0;
int64_t const innerLoopMask = 1 << innerLoopOffset;
size_t const outerLoopOffset = 1;
int64_t const outerLoopMask = 1 << outerLoopOffset;
size_t const bundleInstructionsOffset = 1;
// Returns the number of instructions in the bundle
size_t bundleSize(MCInst const &MCI);
// Returns a iterator range of instructions in this bundle
iterator_range<MCInst::const_iterator> bundleInstructions(MCInst const &MCI);
// Return memory access size
HexagonII::MemAccessSize getAccessSize(MCInstrInfo const &MCII,
@ -48,8 +60,6 @@ unsigned getExtentAlignment(MCInstrInfo const &MCII, MCInst const &MCI);
// Return the number of logical bits of the extendable operand
unsigned getExtentBits(MCInstrInfo const &MCII, MCInst const &MCI);
std::bitset<16> GetImplicitBits(MCInst const &MCI);
// Return the max value that a constant extendable operand can have
// without being extended.
int getMaxValue(MCInstrInfo const &MCII, MCInst const &MCI);
@ -61,8 +71,11 @@ int getMinValue(MCInstrInfo const &MCII, MCInst const &MCI);
// Return instruction name
char const *getName(MCInstrInfo const &MCII, MCInst const &MCI);
// Return the operand index for the new value.
unsigned short getNewValueOp(MCInstrInfo const &MCII, MCInst const &MCI);
// Return the operand that consumes or produces a new value.
MCOperand const &getNewValue(MCInstrInfo const &MCII, MCInst const &MCI);
MCOperand const &getNewValueOperand(MCInstrInfo const &MCII, MCInst const &MCI);
// Return the Hexagon ISA class for the insn.
unsigned getType(MCInstrInfo const &MCII, MCInst const &MCI);
@ -70,6 +83,9 @@ unsigned getType(MCInstrInfo const &MCII, MCInst const &MCI);
// Return whether the instruction is a legal new-value producer.
bool hasNewValue(MCInstrInfo const &MCII, MCInst const &MCI);
// Returns whether this MCInst is a wellformed bundle
bool isBundle(MCInst const &MCI);
// Return whether the insn is an actual insn.
bool isCanon(MCInstrInfo const &MCII, MCInst const &MCI);
@ -82,6 +98,12 @@ bool isExtendable(MCInstrInfo const &MCII, MCInst const &MCI);
// Return whether the instruction must be always extended.
bool isExtended(MCInstrInfo const &MCII, MCInst const &MCI);
// Returns whether this instruction is an immediate extender
bool isImmext(MCInst const &MCI);
// Returns whether this bundle is an endloop0
bool isInnerLoop(MCInst const &MCI);
// Return whether the insn is a new-value consumer.
bool isNewValue(MCInstrInfo const &MCII, MCInst const &MCI);
@ -89,9 +111,14 @@ bool isNewValue(MCInstrInfo const &MCII, MCInst const &MCI);
bool isOperandExtended(MCInstrInfo const &MCII, MCInst const &MCI,
unsigned short OperandNum);
bool isPacketBegin(MCInst const &MCI);
// Returns whether this bundle is an endloop1
bool isOuterLoop(MCInst const &MCI);
bool isPacketEnd(MCInst const &MCI);
// Return whether this instruction is predicated
bool isPredicated(MCInstrInfo const &MCII, MCInst const &MCI);
// Return whether the predicate sense is true
bool isPredicatedTrue(MCInstrInfo const &MCII, MCInst const &MCI);
// Return whether the insn is a prefix.
bool isPrefix(MCInstrInfo const &MCII, MCInst const &MCI);
@ -99,23 +126,14 @@ bool isPrefix(MCInstrInfo const &MCII, MCInst const &MCI);
// Return whether the insn is solo, i.e., cannot be in a packet.
bool isSolo(MCInstrInfo const &MCII, MCInst const &MCI);
static const size_t packetBeginIndex = 0;
static const size_t packetEndIndex = 1;
// Pad the bundle with nops to satisfy endloop requirements
void padEndloop(MCInst &MCI);
void resetPacket(MCInst &MCI);
// Marks a bundle as endloop0
void setInnerLoop(MCInst &MCI);
inline void SanityCheckImplicitOperands(MCInst const &MCI) {
assert(MCI.getNumOperands() >= 2 && "At least the two implicit operands");
assert(MCI.getOperand(MCI.getNumOperands() - 1).isInst() &&
"Implicit bits and flags");
assert(MCI.getOperand(MCI.getNumOperands() - 2).isImm() && "Parent pointer");
}
void SetImplicitBits(MCInst &MCI, std::bitset<16> Bits);
void setPacketBegin(MCInst &MCI, bool Y);
void setPacketEnd(MCInst &MCI, bool Y);
// Marks a bundle as endloop1
void setOuterLoop(MCInst &MCI);
}
}

View File

@ -1,4 +1,5 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
; XFAIL:
; Check that the packetizer generates valid packets with constant
; extended instructions.

View File

@ -1,4 +1,5 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
; XFAIL:
; Check that the packetizer generates valid packets with constant
; extended add and base+offset store instructions.

View File

@ -1,5 +1,5 @@
;; RUN: llc -mtriple=hexagon-unknown-elf -filetype=obj %s -o - \
;; RUN: | llvm-objdump -s - | FileCheck %s
;; RUN: | llvm-objdump -d - | FileCheck %s
define i1 @foo (i32 %a, i32 %b)
{
@ -7,4 +7,6 @@ define i1 @foo (i32 %a, i32 %b)
ret i1 %1
}
; CHECK: 0000 004100f2 00404089 00c09f52
; CHECK: p0 = cmp.eq(r0, r1)
; CHECK: r0 = p0
; CHECK: jumpr r31

View File

@ -1,5 +1,5 @@
;; RUN: llc -mtriple=hexagon-unknown-elf -filetype=obj %s -o - \
;; RUN: | llvm-objdump -s - | FileCheck %s
;; RUN: | llvm-objdump -d - | FileCheck %s
define i1 @foo (i32 %a)
{
@ -7,4 +7,6 @@ define i1 @foo (i32 %a)
ret i1 %1
}
; CHECK: 0000 40450075 00404089 00c09f52
; CHECK: p0 = cmp.eq(r0, #42)
; CHECK: r0 = p0
; CHECK: jumpr r31

View File

@ -1,5 +1,5 @@
;; RUN: llc -mtriple=hexagon-unknown-elf -filetype=obj %s -o - \
;; RUN: | llvm-objdump -s - | FileCheck %s
;; RUN: | llvm-objdump -d - | FileCheck %s
define i1 @foo (i32 %a, i32 %b)
{
@ -7,4 +7,6 @@ define i1 @foo (i32 %a, i32 %b)
ret i1 %1
}
; CHECK: 0000 004140f2 00404089 00c09f52
; CHECK: p0 = cmp.gt(r0, r1)
; CHECK: r0 = p0
; CHECK: jumpr r31 }

View File

@ -1,5 +1,5 @@
;; RUN: llc -mtriple=hexagon-unknown-elf -filetype=obj %s -o - \
;; RUN: | llvm-objdump -s - | FileCheck %s
;; RUN: | llvm-objdump -d - | FileCheck %s
define i1 @foo (i32 %a)
{
@ -7,4 +7,6 @@ define i1 @foo (i32 %a)
ret i1 %1
}
; CHECK: 0000 40454075 00404089 00c09f52
; CHECK: p0 = cmp.gt(r0, #42)
; CHECK: r0 = p0
; CHECK: jumpr r31

View File

@ -1,5 +1,5 @@
;; RUN: llc -mtriple=hexagon-unknown-elf -filetype=obj %s -o - \
;; RUN: | llvm-objdump -s - | FileCheck %s
;; RUN: | llvm-objdump -d - | FileCheck %s
define i1 @foo (i32 %a, i32 %b)
{
@ -7,4 +7,6 @@ define i1 @foo (i32 %a, i32 %b)
ret i1 %1
}
; CHECK: 0000 004041f2 00404089 00c09f52
; CHECK: p0 = cmp.gt(r1, r0)
; CHECK: r0 = p0
; CHECK: jumpr r31

View File

@ -1,5 +1,5 @@
;; RUN: llc -mtriple=hexagon-unknown-elf -filetype=obj %s -o - \
;; RUN: | llvm-objdump -s - | FileCheck %s
;; RUN: | llvm-objdump -d - | FileCheck %s
define i1 @foo (i32 %a, i32 %b)
{
@ -7,4 +7,6 @@ define i1 @foo (i32 %a, i32 %b)
ret i1 %1
}
; CHECK: 0000 004160f2 00404089 00c09f52
; CHECK: p0 = cmp.gtu(r0, r1)
; CHECK: r0 = p0
; CHECK: jumpr r31

View File

@ -1,5 +1,5 @@
;; RUN: llc -mtriple=hexagon-unknown-elf -filetype=obj %s -o - \
;; RUN: | llvm-objdump -s - | FileCheck %s
;; RUN: | llvm-objdump -d - | FileCheck %s
define i1 @foo (i32 %a)
{
@ -7,4 +7,6 @@ define i1 @foo (i32 %a)
ret i1 %1
}
; CHECK: 0000 40458075 00404089 00c09f52
; CHECK: p0 = cmp.gtu(r0, #42)
; CHECK: r0 = p0
; CHECK: jumpr r31

View File

@ -1,5 +1,5 @@
;; RUN: llc -mtriple=hexagon-unknown-elf -filetype=obj %s -o - \
;; RUN: | llvm-objdump -s - | FileCheck %s
;; RUN: | llvm-objdump -d - | FileCheck %s
define i1 @foo (i32 %a, i32 %b)
{
@ -7,4 +7,6 @@ define i1 @foo (i32 %a, i32 %b)
ret i1 %1
}
; CHECK: 0000 004061f2 00404089 00c09f52
; CHECK: p0 = cmp.gtu(r1, r0)
; CHECK: r0 = p0
; CHECK: jumpr r31

View File

@ -205,7 +205,7 @@ namespace {
class PrettyPrinter {
public:
virtual ~PrettyPrinter(){}
virtual void printInst(MCInstPrinter &IP, const MCInst *MI, bool ShowRawInsn,
virtual void printInst(MCInstPrinter &IP, const MCInst *MI,
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &OS, StringRef Annot,
MCSubtargetInfo const &STI) {
@ -218,8 +218,66 @@ public:
}
};
PrettyPrinter PrettyPrinterInst;
class HexagonPrettyPrinter : public PrettyPrinter {
public:
void printLead(ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &OS) {
uint32_t opcode =
(Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0];
OS << format("%8" PRIx64 ":", Address);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes.slice(0, 4), OS);
OS << format("%08" PRIx32, opcode);
}
}
void printInst(MCInstPrinter &IP, const MCInst *MI,
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &OS, StringRef Annot,
MCSubtargetInfo const &STI) override {
std::string Buffer;
{
raw_string_ostream TempStream(Buffer);
IP.printInst(MI, TempStream, "", STI);
}
StringRef Contents(Buffer);
// Split off bundle attributes
auto PacketBundle = Contents.rsplit('\n');
// Split off first instruction from the rest
auto HeadTail = PacketBundle.first.split('\n');
auto Preamble = " { ";
auto Separator = "";
while(!HeadTail.first.empty()) {
OS << Separator;
Separator = "\n";
printLead(Bytes, Address, OS);
OS << Preamble;
Preamble = " ";
StringRef Inst;
auto Duplex = HeadTail.first.split('\v');
if(!Duplex.second.empty()){
OS << Duplex.first;
OS << "; ";
Inst = Duplex.second;
}
else
Inst = HeadTail.first;
OS << Inst;
Bytes = Bytes.slice(4);
Address += 4;
HeadTail = HeadTail.second.split('\n');
}
OS << " } " << PacketBundle.second;
}
};
HexagonPrettyPrinter HexagonPrettyPrinterInst;
PrettyPrinter &selectPrettyPrinter(Triple const &Triple, MCInstPrinter &IP) {
return PrettyPrinterInst;
switch(Triple.getArch()) {
default:
return PrettyPrinterInst;
case Triple::hexagon:
return HexagonPrettyPrinterInst;
}
}
}
@ -406,7 +464,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
if (DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
SectionAddr + Index, DebugOut,
CommentStream)) {
PIP.printInst(*IP, &Inst, !NoShowRawInsn,
PIP.printInst(*IP, &Inst,
Bytes.slice(Index, Size),
SectionAddr + Index, outs(), "", *STI);
outs() << CommentStream.str();