//
//===----------------------------------------------------------------------===//
+#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"
#include <vector>
using namespace llvm;
+using namespace Hexagon;
#define DEBUG_TYPE "hexagon-disassembler"
/// \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,
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;
+
+ *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;
+}
- uint32_t insn =
+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;
}
// 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
/// the current output stream.
///
void HexagonAsmPrinter::EmitInstruction(const MachineInstr *MI) {
- if (MI->isBundle()) {
- std::vector<MachineInstr const *> BundleMIs;
+ MCInst MCB;
+ MCB.setOpcode(Hexagon::BUNDLE);
+ MCB.addOperand(MCOperand::createImm(0));
- const MachineBasicBlock *MBB = MI->getParent();
+ if (MI->isBundle()) {
+ 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;
+ unsigned IgnoreCount = 0;
+
+ 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);
}
- // 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;
-
- HexagonLowerToMC(BundleMIs[Index], MCI, *this);
- HexagonMCInstrInfo::AppendImplicitOperands(MCI);
- HexagonMCInstrInfo::setPacketBegin(MCI, Index == 0);
- HexagonMCInstrInfo::setPacketEnd(MCI, Index == (Size - 1));
- EmitToStreamer(*OutStreamer, MCI);
}
}
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;
}
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;
}
#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"
}
// 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);
break;
}
- MCI.addOperand(MCO);
+ MCI->addOperand(MCO);
}
+ MCB.addOperand(MCOperand::createInst(MCI));
}
MO_GPREL
};
- enum class InstParseBits : uint32_t {
+ enum InstParseBits {
INST_PARSE_MASK = 0x0000c000,
INST_PARSE_PACKET_END = 0x0000c000,
INST_PARSE_LOOP_END = 0x00008000,
#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) {
OS << getRegisterName(RegNo);
}
-void HexagonInstPrinter::printInst(MCInst const *MI, raw_ostream &O,
- 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);
- }
+void HexagonInstPrinter::setExtender(MCInst const &MCI) {
+ HasExtender = HexagonMCInstrInfo::isImmext(MCI);
+}
- // Close the packet.
- if (HexagonMCInstrInfo::isPacketEnd(*MI))
- O << PacketPadding << endPacket;
+void HexagonInstPrinter::printInst(MCInst const *MI, raw_ostream &OS,
+ StringRef Annot,
+ 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";
+ }
- printInstruction(MI, O);
+ auto Separator = "";
+ if (HexagonMCInstrInfo::isInnerLoop(*MI)) {
+ OS << Separator;
+ Separator = " ";
+ MCInst ME;
+ ME.setOpcode(Hexagon::ENDLOOP0);
+ printInstruction(&ME, OS);
}
- 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;
+ if (HexagonMCInstrInfo::isOuterLoop(*MI)) {
+ OS << Separator;
+ Separator = " ";
+ MCInst ME;
+ ME.setOpcode(Hexagon::ENDLOOP1);
+ printInstruction(&ME, OS);
}
-
- printAnnotation(O, Annot);
}
void HexagonInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
#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,
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
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);
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;
}
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,
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,
//
//===----------------------------------------------------------------------===//
-#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
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,
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;
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() &&
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) {
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.
return ((F >> HexagonII::SoloPos) & HexagonII::SoloMask);
}
-void HexagonMCInstrInfo::resetPacket(MCInst &MCI) {
- setPacketBegin(MCI, false);
- setPacketEnd(MCI, false);
-}
-
-void HexagonMCInstrInfo::SetImplicitBits(MCInst &MCI, std::bitset<16> Bits) {
- SanityCheckImplicitOperands(MCI);
- MCI.getOperand(MCI.getNumOperands() - 2).setImm(Bits.to_ulong());
+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::setPacketBegin(MCInst &MCI, bool f) {
- std::bitset<16> Bits(GetImplicitBits(MCI));
- Bits.set(packetBeginIndex, f);
- SetImplicitBits(MCI, Bits);
+void HexagonMCInstrInfo::setInnerLoop(MCInst &MCI) {
+ assert(isBundle(MCI));
+ MCOperand &Operand = MCI.getOperand(0);
+ Operand.setImm(Operand.getImm() | innerLoopMask);
}
-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);
}
}
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,
// 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);
// 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);
// 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);
// 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);
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);
// 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;
-
-void resetPacket(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);
+// Pad the bundle with nops to satisfy endloop requirements
+void padEndloop(MCInst &MCI);
-void setPacketBegin(MCInst &MCI, bool Y);
+// Marks a bundle as endloop0
+void setInnerLoop(MCInst &MCI);
-void setPacketEnd(MCInst &MCI, bool Y);
+// Marks a bundle as endloop1
+void setOuterLoop(MCInst &MCI);
}
}
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
+; XFAIL:
; Check that the packetizer generates valid packets with constant
; extended instructions.
; 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.
;; 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)
{
ret i1 %1
}
-; CHECK: 0000 004100f2 00404089 00c09f52
+; CHECK: p0 = cmp.eq(r0, r1)
+; CHECK: r0 = p0
+; CHECK: jumpr r31
;; 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)
{
ret i1 %1
}
-; CHECK: 0000 40450075 00404089 00c09f52
+; CHECK: p0 = cmp.eq(r0, #42)
+; CHECK: r0 = p0
+; CHECK: jumpr r31
;; 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)
{
ret i1 %1
}
-; CHECK: 0000 004140f2 00404089 00c09f52
+; CHECK: p0 = cmp.gt(r0, r1)
+; CHECK: r0 = p0
+; CHECK: jumpr r31 }
\ No newline at end of file
;; 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)
{
ret i1 %1
}
-; CHECK: 0000 40454075 00404089 00c09f52
+; CHECK: p0 = cmp.gt(r0, #42)
+; CHECK: r0 = p0
+; CHECK: jumpr r31
;; 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)
{
ret i1 %1
}
-; CHECK: 0000 004041f2 00404089 00c09f52
+; CHECK: p0 = cmp.gt(r1, r0)
+; CHECK: r0 = p0
+; CHECK: jumpr r31
;; 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)
{
ret i1 %1
}
-; CHECK: 0000 004160f2 00404089 00c09f52
+; CHECK: p0 = cmp.gtu(r0, r1)
+; CHECK: r0 = p0
+; CHECK: jumpr r31
;; 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)
{
ret i1 %1
}
-; CHECK: 0000 40458075 00404089 00c09f52
+; CHECK: p0 = cmp.gtu(r0, #42)
+; CHECK: r0 = p0
+; CHECK: jumpr r31
;; 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)
{
ret i1 %1
}
-; CHECK: 0000 004061f2 00404089 00c09f52
+; CHECK: p0 = cmp.gtu(r1, r0)
+; CHECK: r0 = p0
+; CHECK: jumpr r31
\ No newline at end of file
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) {
}
};
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;
+ }
}
}
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();