From: Colin LeMahieu Date: Mon, 9 Nov 2015 04:07:48 +0000 (+0000) Subject: [Hexagon] Enabling ASM parsing on Hexagon backend and adding instruction parsing... X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=c0aef701ccc74df06048be730ec82e7c34a6ebcf [Hexagon] Enabling ASM parsing on Hexagon backend and adding instruction parsing tests. General updating of the code emission. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252443 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/Hexagon/AsmParser/CMakeLists.txt b/lib/Target/Hexagon/AsmParser/CMakeLists.txt new file mode 100644 index 00000000000..bbfa92d5962 --- /dev/null +++ b/lib/Target/Hexagon/AsmParser/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMHexagonAsmParser + HexagonAsmParser.cpp + ) + +add_dependencies( LLVMHexagonAsmParser HexagonCommonTableGen ) diff --git a/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp b/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp new file mode 100644 index 00000000000..ee3d177d07d --- /dev/null +++ b/lib/Target/Hexagon/AsmParser/HexagonAsmParser.cpp @@ -0,0 +1,2152 @@ +//===-- HexagonAsmParser.cpp - Parse Hexagon asm to MCInst instructions----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mcasmparser" + +#include "Hexagon.h" +#include "HexagonRegisterInfo.h" +#include "HexagonTargetStreamer.h" +#include "MCTargetDesc/HexagonBaseInfo.h" +#include "MCTargetDesc/HexagonMCELFStreamer.h" +#include "MCTargetDesc/HexagonMCChecker.h" +#include "MCTargetDesc/HexagonMCExpr.h" +#include "MCTargetDesc/HexagonMCShuffler.h" +#include "MCTargetDesc/HexagonMCTargetDesc.h" +#include "MCTargetDesc/HexagonMCAsmInfo.h" +#include "MCTargetDesc/HexagonShuffler.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; + +static cl::opt EnableFutureRegs("mfuture-regs", + cl::desc("Enable future registers")); + +static cl::opt WarnMissingParenthesis("mwarn-missing-parenthesis", +cl::desc("Warn for missing parenthesis around predicate registers"), +cl::init(true)); +static cl::opt ErrorMissingParenthesis("merror-missing-parenthesis", +cl::desc("Error for missing parenthesis around predicate registers"), +cl::init(false)); +static cl::opt WarnSignedMismatch("mwarn-sign-mismatch", +cl::desc("Warn for mismatching a signed and unsigned value"), +cl::init(true)); +static cl::opt WarnNoncontigiousRegister("mwarn-noncontigious-register", +cl::desc("Warn for register names that arent contigious"), +cl::init(true)); +static cl::opt ErrorNoncontigiousRegister("merror-noncontigious-register", +cl::desc("Error for register names that aren't contigious"), +cl::init(false)); + + +namespace { +struct HexagonOperand; + +class HexagonAsmParser : public MCTargetAsmParser { + + HexagonTargetStreamer &getTargetStreamer() { + MCTargetStreamer &TS = *Parser.getStreamer().getTargetStreamer(); + return static_cast(TS); + } + + MCSubtargetInfo &STI; + MCAsmParser &Parser; + MCAssembler *Assembler; + MCInstrInfo const &MCII; + MCInst MCB; + bool InBrackets; + + MCAsmParser &getParser() const { return Parser; } + MCAssembler *getAssembler() const { return Assembler; } + MCAsmLexer &getLexer() const { return Parser.getLexer(); } + + unsigned ArchVersion; + + bool equalIsAsmAssignment() override { return false; } + bool isLabel(AsmToken &Token) override; + + void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); } + bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } + bool ParseDirectiveFalign(unsigned Size, SMLoc L); + + virtual bool ParseRegister(unsigned &RegNo, + SMLoc &StartLoc, + SMLoc &EndLoc) override; + bool ParseDirectiveSubsection(SMLoc L); + bool ParseDirectiveValue(unsigned Size, SMLoc L); + bool ParseDirectiveComm(bool IsLocal, SMLoc L); + bool RegisterMatchesArch(unsigned MatchNum) const; + + bool matchBundleOptions(); + bool handleNoncontigiousRegister(bool Contigious, SMLoc &Loc); + bool finishBundle(SMLoc IDLoc, MCStreamer &Out); + void canonicalizeImmediates(MCInst &MCI); + bool matchOneInstruction(MCInst &MCB, SMLoc IDLoc, + OperandVector &InstOperands, uint64_t &ErrorInfo, + bool MatchingInlineAsm, bool &MustExtend); + + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, bool MatchingInlineAsm); + + unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; + void OutOfRange(SMLoc IDLoc, long long Val, long long Max); + int processInstruction(MCInst &Inst, OperandVector const &Operands, + SMLoc IDLoc, bool &MustExtend); + + // Check if we have an assembler and, if so, set the ELF e_header flags. + void chksetELFHeaderEFlags(unsigned flags) { + if (getAssembler()) + getAssembler()->setELFHeaderEFlags(flags); + } + +/// @name Auto-generated Match Functions +/// { + +#define GET_ASSEMBLER_HEADER +#include "HexagonGenAsmMatcher.inc" + + /// } + +public: + HexagonAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(Options), STI(_STI), Parser(_Parser), + MCII (MII), InBrackets(false) { + MCB.setOpcode(Hexagon::BUNDLE); + setAvailableFeatures( + ComputeAvailableFeatures(_STI.getFeatureBits())); + + MCAsmParserExtension::Initialize(_Parser); + + Assembler = nullptr; + // FIXME: need better way to detect AsmStreamer (upstream removed getKind()) + if (!Parser.getStreamer().hasRawTextSupport()) { + MCELFStreamer *MES = static_cast(&Parser.getStreamer()); + Assembler = &MES->getAssembler(); + } + } + + bool mustExtend(OperandVector &Operands); + bool splitIdentifier(OperandVector &Operands); + bool parseOperand(OperandVector &Operands); + bool parseInstruction(OperandVector &Operands); + bool implicitExpressionLocation(OperandVector &Operands); + bool parseExpressionOrOperand(OperandVector &Operands); + bool parseExpression(MCExpr const *& Expr); + virtual bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { + llvm_unreachable("Unimplemented"); + } + virtual bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + AsmToken ID, OperandVector &Operands); + + virtual bool ParseDirective(AsmToken DirectiveID); +}; + +/// HexagonOperand - Instances of this class represent a parsed Hexagon machine +/// instruction. +struct HexagonOperand : public MCParsedAsmOperand { + enum KindTy { Token, Immediate, Register } Kind; + + SMLoc StartLoc, EndLoc; + + struct TokTy { + const char *Data; + unsigned Length; + }; + + struct RegTy { + unsigned RegNum; + }; + + struct ImmTy { + const MCExpr *Val; + bool MustExtend; + }; + + struct InstTy { + OperandVector *SubInsts; + }; + + union { + struct TokTy Tok; + struct RegTy Reg; + struct ImmTy Imm; + }; + + HexagonOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} + +public: + HexagonOperand(const HexagonOperand &o) : MCParsedAsmOperand() { + Kind = o.Kind; + StartLoc = o.StartLoc; + EndLoc = o.EndLoc; + switch (Kind) { + case Register: + Reg = o.Reg; + break; + case Immediate: + Imm = o.Imm; + break; + case Token: + Tok = o.Tok; + break; + } + } + + /// getStartLoc - Get the location of the first token of this operand. + SMLoc getStartLoc() const { return StartLoc; } + + /// getEndLoc - Get the location of the last token of this operand. + SMLoc getEndLoc() const { return EndLoc; } + + unsigned getReg() const { + assert(Kind == Register && "Invalid access!"); + return Reg.RegNum; + } + + const MCExpr *getImm() const { + assert(Kind == Immediate && "Invalid access!"); + return Imm.Val; + } + + bool isToken() const { return Kind == Token; } + bool isImm() const { return Kind == Immediate; } + bool isMem() const { llvm_unreachable("No isMem"); } + bool isReg() const { return Kind == Register; } + + bool CheckImmRange(int immBits, int zeroBits, bool isSigned, + bool isRelocatable, bool Extendable) const { + if (Kind == Immediate) { + const MCExpr *myMCExpr = getImm(); + if (Imm.MustExtend && !Extendable) + return false; + int64_t Res; + if (myMCExpr->evaluateAsAbsolute(Res)) { + int bits = immBits + zeroBits; + // Field bit range is zerobits + bits + // zeroBits must be 0 + if (Res & ((1 << zeroBits) - 1)) + return false; + if (isSigned) { + if (Res < (1LL << (bits - 1)) && Res >= -(1LL << (bits - 1))) + return true; + } else { + if (bits == 64) + return true; + if (Res >= 0) + return ((uint64_t)Res < (uint64_t)(1ULL << bits)) ? true : false; + else { + const int64_t high_bit_set = 1ULL << 63; + const uint64_t mask = (high_bit_set >> (63 - bits)); + return (((uint64_t)Res & mask) == mask) ? true : false; + } + } + } else if (myMCExpr->getKind() == MCExpr::SymbolRef && isRelocatable) + return true; + else if (myMCExpr->getKind() == MCExpr::Binary || + myMCExpr->getKind() == MCExpr::Unary) + return true; + } + return false; + } + + bool isf32Ext() const { return false; } + bool iss32Imm() const { return CheckImmRange(32, 0, true, true, false); } + bool iss8Imm() const { return CheckImmRange(8, 0, true, false, false); } + bool iss8Imm64() const { return CheckImmRange(8, 0, true, true, false); } + bool iss7Imm() const { return CheckImmRange(7, 0, true, false, false); } + bool iss6Imm() const { return CheckImmRange(6, 0, true, false, false); } + bool iss4Imm() const { return CheckImmRange(4, 0, true, false, false); } + bool iss4_0Imm() const { return CheckImmRange(4, 0, true, false, false); } + bool iss4_1Imm() const { return CheckImmRange(4, 1, true, false, false); } + bool iss4_2Imm() const { return CheckImmRange(4, 2, true, false, false); } + bool iss4_3Imm() const { return CheckImmRange(4, 3, true, false, false); } + bool iss4_6Imm() const { return CheckImmRange(4, 0, true, false, false); } + bool iss3_6Imm() const { return CheckImmRange(3, 0, true, false, false); } + bool iss3Imm() const { return CheckImmRange(3, 0, true, false, false); } + + bool isu64Imm() const { return CheckImmRange(64, 0, false, true, true); } + bool isu32Imm() const { return CheckImmRange(32, 0, false, true, false); } + bool isu26_6Imm() const { return CheckImmRange(26, 6, false, true, false); } + bool isu16Imm() const { return CheckImmRange(16, 0, false, true, false); } + bool isu16_0Imm() const { return CheckImmRange(16, 0, false, true, false); } + bool isu16_1Imm() const { return CheckImmRange(16, 1, false, true, false); } + bool isu16_2Imm() const { return CheckImmRange(16, 2, false, true, false); } + bool isu16_3Imm() const { return CheckImmRange(16, 3, false, true, false); } + bool isu11_3Imm() const { return CheckImmRange(11, 3, false, false, false); } + bool isu6_0Imm() const { return CheckImmRange(6, 0, false, false, false); } + bool isu6_1Imm() const { return CheckImmRange(6, 1, false, false, false); } + bool isu6_2Imm() const { return CheckImmRange(6, 2, false, false, false); } + bool isu6_3Imm() const { return CheckImmRange(6, 3, false, false, false); } + bool isu10Imm() const { return CheckImmRange(10, 0, false, false, false); } + bool isu9Imm() const { return CheckImmRange(9, 0, false, false, false); } + bool isu8Imm() const { return CheckImmRange(8, 0, false, false, false); } + bool isu7Imm() const { return CheckImmRange(7, 0, false, false, false); } + bool isu6Imm() const { return CheckImmRange(6, 0, false, false, false); } + bool isu5Imm() const { return CheckImmRange(5, 0, false, false, false); } + bool isu4Imm() const { return CheckImmRange(4, 0, false, false, false); } + bool isu3Imm() const { return CheckImmRange(3, 0, false, false, false); } + bool isu2Imm() const { return CheckImmRange(2, 0, false, false, false); } + bool isu1Imm() const { return CheckImmRange(1, 0, false, false, false); } + + bool ism6Imm() const { return CheckImmRange(6, 0, false, false, false); } + bool isn8Imm() const { return CheckImmRange(8, 0, false, false, false); } + + bool iss16Ext() const { return CheckImmRange(16 + 26, 0, true, true, true); } + bool iss12Ext() const { return CheckImmRange(12 + 26, 0, true, true, true); } + bool iss10Ext() const { return CheckImmRange(10 + 26, 0, true, true, true); } + bool iss9Ext() const { return CheckImmRange(9 + 26, 0, true, true, true); } + bool iss8Ext() const { return CheckImmRange(8 + 26, 0, true, true, true); } + bool iss7Ext() const { return CheckImmRange(7 + 26, 0, true, true, true); } + bool iss6Ext() const { return CheckImmRange(6 + 26, 0, true, true, true); } + bool iss11_0Ext() const { + return CheckImmRange(11 + 26, 0, true, true, true); + } + bool iss11_1Ext() const { + return CheckImmRange(11 + 26, 1, true, true, true); + } + bool iss11_2Ext() const { + return CheckImmRange(11 + 26, 2, true, true, true); + } + bool iss11_3Ext() const { + return CheckImmRange(11 + 26, 3, true, true, true); + } + + bool isu6Ext() const { return CheckImmRange(6 + 26, 0, false, true, true); } + bool isu7Ext() const { return CheckImmRange(7 + 26, 0, false, true, true); } + bool isu8Ext() const { return CheckImmRange(8 + 26, 0, false, true, true); } + bool isu9Ext() const { return CheckImmRange(9 + 26, 0, false, true, true); } + bool isu10Ext() const { return CheckImmRange(10 + 26, 0, false, true, true); } + bool isu6_0Ext() const { return CheckImmRange(6 + 26, 0, false, true, true); } + bool isu6_1Ext() const { return CheckImmRange(6 + 26, 1, false, true, true); } + bool isu6_2Ext() const { return CheckImmRange(6 + 26, 2, false, true, true); } + bool isu6_3Ext() const { return CheckImmRange(6 + 26, 3, false, true, true); } + bool isu32MustExt() const { return isImm() && Imm.MustExtend; } + + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getReg())); + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createExpr(getImm())); + } + + void addSignedImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + MCExpr const *Expr = getImm(); + int64_t Value; + if (!Expr->evaluateAsAbsolute(Value)) { + Inst.addOperand(MCOperand::createExpr(Expr)); + return; + } + int64_t Extended = SignExtend64 (Value, 32); + if ((Extended < 0) == (Value < 0)) { + Inst.addOperand(MCOperand::createExpr(Expr)); + return; + } + // Flip bit 33 to signal signed unsigned mismatch + Extended ^= 0x100000000; + Inst.addOperand(MCOperand::createImm(Extended)); + } + + void addf32ExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + + void adds32ImmOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds8ImmOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds8Imm64Operands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds6ImmOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds4ImmOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds4_0ImmOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds4_1ImmOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds4_2ImmOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds4_3ImmOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds3ImmOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + + void addu64ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu32ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu26_6ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu16ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu16_0ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu16_1ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu16_2ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu16_3ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu11_3ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu10ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu9ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu8ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu7ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu6ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu6_0ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu6_1ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu6_2ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu6_3ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu5ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu4ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu3ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu2ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu1ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + + void addm6ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addn8ImmOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + + void adds16ExtOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds12ExtOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds10ExtOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds9ExtOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds8ExtOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds6ExtOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds11_0ExtOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds11_1ExtOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds11_2ExtOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + void adds11_3ExtOperands(MCInst &Inst, unsigned N) const { + addSignedImmOperands(Inst, N); + } + + void addu6ExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu7ExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu8ExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu9ExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu10ExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu6_0ExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu6_1ExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu6_2ExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu6_3ExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + void addu32MustExtOperands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + + void adds4_6ImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *CE = dyn_cast(getImm()); + Inst.addOperand(MCOperand::createImm(CE->getValue() << 6)); + } + + void adds3_6ImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCConstantExpr *CE = dyn_cast(getImm()); + Inst.addOperand(MCOperand::createImm(CE->getValue() << 6)); + } + + StringRef getToken() const { + assert(Kind == Token && "Invalid access!"); + return StringRef(Tok.Data, Tok.Length); + } + + virtual void print(raw_ostream &OS) const; + + static std::unique_ptr CreateToken(StringRef Str, SMLoc S) { + HexagonOperand *Op = new HexagonOperand(Token); + Op->Tok.Data = Str.data(); + Op->Tok.Length = Str.size(); + Op->StartLoc = S; + Op->EndLoc = S; + return std::unique_ptr(Op); + } + + static std::unique_ptr CreateReg(unsigned RegNum, SMLoc S, + SMLoc E) { + HexagonOperand *Op = new HexagonOperand(Register); + Op->Reg.RegNum = RegNum; + Op->StartLoc = S; + Op->EndLoc = E; + return std::unique_ptr(Op); + } + + static std::unique_ptr CreateImm(const MCExpr *Val, SMLoc S, + SMLoc E) { + HexagonOperand *Op = new HexagonOperand(Immediate); + Op->Imm.Val = Val; + Op->Imm.MustExtend = false; + Op->StartLoc = S; + Op->EndLoc = E; + return std::unique_ptr(Op); + } +}; + +} // end anonymous namespace. + +void HexagonOperand::print(raw_ostream &OS) const { + switch (Kind) { + case Immediate: + getImm()->print(OS, nullptr); + break; + case Register: + OS << ""; + break; + case Token: + OS << "'" << getToken() << "'"; + break; + } +} + +/// @name Auto-generated Match Functions +static unsigned MatchRegisterName(StringRef Name); + +bool HexagonAsmParser::finishBundle(SMLoc IDLoc, MCStreamer &Out) { + DEBUG(dbgs() << "Bundle:"); + DEBUG(MCB.dump_pretty(dbgs())); + DEBUG(dbgs() << "--\n"); + + // Check the bundle for errors. + const MCRegisterInfo *RI = getContext().getRegisterInfo(); + HexagonMCChecker Check(MCII, STI, MCB, MCB, *RI); + + bool CheckOk = HexagonMCInstrInfo::canonicalizePacket(MCII, STI, getContext(), + MCB, &Check); + + while (Check.getNextErrInfo() == true) { + unsigned Reg = Check.getErrRegister(); + Twine R(RI->getName(Reg)); + + uint64_t Err = Check.getError(); + if (Err != HexagonMCErrInfo::CHECK_SUCCESS) { + if (HexagonMCErrInfo::CHECK_ERROR_BRANCHES & Err) + Error(IDLoc, + "unconditional branch cannot precede another branch in packet"); + + if (HexagonMCErrInfo::CHECK_ERROR_NEWP & Err || + HexagonMCErrInfo::CHECK_ERROR_NEWV & Err) + Error(IDLoc, "register `" + R + + "' used with `.new' " + "but not validly modified in the same packet"); + + if (HexagonMCErrInfo::CHECK_ERROR_REGISTERS & Err) + Error(IDLoc, "register `" + R + "' modified more than once"); + + if (HexagonMCErrInfo::CHECK_ERROR_READONLY & Err) + Error(IDLoc, "cannot write to read-only register `" + R + "'"); + + if (HexagonMCErrInfo::CHECK_ERROR_LOOP & Err) + Error(IDLoc, "loop-setup and some branch instructions " + "cannot be in the same packet"); + + if (HexagonMCErrInfo::CHECK_ERROR_ENDLOOP & Err) { + Twine N(HexagonMCInstrInfo::isInnerLoop(MCB) ? '0' : '1'); + Error(IDLoc, "packet marked with `:endloop" + N + "' " + + "cannot contain instructions that modify register " + + "`" + R + "'"); + } + + if (HexagonMCErrInfo::CHECK_ERROR_SOLO & Err) + Error(IDLoc, + "instruction cannot appear in packet with other instructions"); + + if (HexagonMCErrInfo::CHECK_ERROR_NOSLOTS & Err) + Error(IDLoc, "too many slots used in packet"); + + if (Err & HexagonMCErrInfo::CHECK_ERROR_SHUFFLE) { + uint64_t Erm = Check.getShuffleError(); + + if (HexagonShuffler::SHUFFLE_ERROR_INVALID == Erm) + Error(IDLoc, "invalid instruction packet"); + else if (HexagonShuffler::SHUFFLE_ERROR_STORES == Erm) + Error(IDLoc, "invalid instruction packet: too many stores"); + else if (HexagonShuffler::SHUFFLE_ERROR_LOADS == Erm) + Error(IDLoc, "invalid instruction packet: too many loads"); + else if (HexagonShuffler::SHUFFLE_ERROR_BRANCHES == Erm) + Error(IDLoc, "too many branches in packet"); + else if (HexagonShuffler::SHUFFLE_ERROR_NOSLOTS == Erm) + Error(IDLoc, "invalid instruction packet: out of slots"); + else if (HexagonShuffler::SHUFFLE_ERROR_SLOTS == Erm) + Error(IDLoc, "invalid instruction packet: slot error"); + else if (HexagonShuffler::SHUFFLE_ERROR_ERRATA2 == Erm) + Error(IDLoc, "v60 packet violation"); + else if (HexagonShuffler::SHUFFLE_ERROR_STORE_LOAD_CONFLICT == Erm) + Error(IDLoc, "slot 0 instruction does not allow slot 1 store"); + else + Error(IDLoc, "unknown error in instruction packet"); + } + } + + unsigned Warn = Check.getWarning(); + if (Warn != HexagonMCErrInfo::CHECK_SUCCESS) { + if (HexagonMCErrInfo::CHECK_WARN_CURRENT & Warn) + Warning(IDLoc, "register `" + R + "' used with `.cur' " + "but not used in the same packet"); + else if (HexagonMCErrInfo::CHECK_WARN_TEMPORARY & Warn) + Warning(IDLoc, "register `" + R + "' used with `.tmp' " + "but not used in the same packet"); + } + } + + if (CheckOk) { + MCB.setLoc(IDLoc); + if (HexagonMCInstrInfo::bundleSize(MCB) == 0) { + assert(!HexagonMCInstrInfo::isInnerLoop(MCB)); + assert(!HexagonMCInstrInfo::isOuterLoop(MCB)); + // Empty packets are valid yet aren't emitted + return false; + } + Out.EmitInstruction(MCB, STI); + } else { + // If compounding and duplexing didn't reduce the size below + // 4 or less we have a packet that is too big. + if (HexagonMCInstrInfo::bundleSize(MCB) > HEXAGON_PACKET_SIZE) { + Error(IDLoc, "invalid instruction packet: out of slots"); + return true; // Error + } + } + + return false; // No error +} + +bool HexagonAsmParser::matchBundleOptions() { + MCAsmParser &Parser = getParser(); + MCAsmLexer &Lexer = getLexer(); + while (true) { + if (!Parser.getTok().is(AsmToken::Colon)) + return false; + Lexer.Lex(); + StringRef Option = Parser.getTok().getString(); + if (Option.compare_lower("endloop0") == 0) + HexagonMCInstrInfo::setInnerLoop(MCB); + else if (Option.compare_lower("endloop1") == 0) + HexagonMCInstrInfo::setOuterLoop(MCB); + else if (Option.compare_lower("mem_noshuf") == 0) + HexagonMCInstrInfo::setMemReorderDisabled(MCB); + else if (Option.compare_lower("mem_shuf") == 0) + HexagonMCInstrInfo::setMemStoreReorderEnabled(MCB); + else + return true; + Lexer.Lex(); + } +} + +// For instruction aliases, immediates are generated rather than +// MCConstantExpr. Convert them for uniform MCExpr. +// Also check for signed/unsigned mismatches and warn +void HexagonAsmParser::canonicalizeImmediates(MCInst &MCI) { + MCInst NewInst; + NewInst.setOpcode(MCI.getOpcode()); + for (MCOperand &I : MCI) + if (I.isImm()) { + int64_t Value (I.getImm()); + if ((Value & 0x100000000) != (Value & 0x80000000)) { + // Detect flipped bit 33 wrt bit 32 and signal warning + Value ^= 0x100000000; + if (WarnSignedMismatch) + Warning (MCI.getLoc(), "Signed/Unsigned mismatch"); + } + NewInst.addOperand(MCOperand::createExpr( + MCConstantExpr::create(Value, getContext()))); + } + else + NewInst.addOperand(I); + MCI = NewInst; +} + +bool HexagonAsmParser::matchOneInstruction(MCInst &MCI, SMLoc IDLoc, + OperandVector &InstOperands, + uint64_t &ErrorInfo, + bool MatchingInlineAsm, + bool &MustExtend) { + // Perform matching with tablegen asmmatcher generated function + int result = + MatchInstructionImpl(InstOperands, MCI, ErrorInfo, MatchingInlineAsm); + if (result == Match_Success) { + MCI.setLoc(IDLoc); + MustExtend = mustExtend(InstOperands); + canonicalizeImmediates(MCI); + result = processInstruction(MCI, InstOperands, IDLoc, MustExtend); + + DEBUG(dbgs() << "Insn:"); + DEBUG(MCI.dump_pretty(dbgs())); + DEBUG(dbgs() << "\n\n"); + + MCI.setLoc(IDLoc); + } + + // Create instruction operand for bundle instruction + // Break this into a separate function Code here is less readable + // Think about how to get an instruction error to report correctly. + // SMLoc will return the "{" + switch (result) { + default: + break; + case Match_Success: + return false; + case Match_MissingFeature: + return Error(IDLoc, "invalid instruction"); + case Match_MnemonicFail: + return Error(IDLoc, "unrecognized instruction"); + case Match_InvalidOperand: + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0U) { + if (ErrorInfo >= InstOperands.size()) + return Error(IDLoc, "too few operands for instruction"); + + ErrorLoc = (static_cast(InstOperands[ErrorInfo].get())) + ->getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + return Error(ErrorLoc, "invalid operand for instruction"); + } + llvm_unreachable("Implement any new match types added!"); +} + +bool HexagonAsmParser::mustExtend(OperandVector &Operands) { + unsigned Count = 0; + for (std::unique_ptr &i : Operands) + if (i->isImm()) + if (static_cast(i.get())->Imm.MustExtend) + ++Count; + // Multiple extenders should have been filtered by iss9Ext et. al. + assert(Count < 2 && "Multiple extenders"); + return Count == 1; +} + +bool HexagonAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) { + if (!InBrackets) { + MCB.clear(); + MCB.addOperand(MCOperand::createImm(0)); + } + HexagonOperand &FirstOperand = static_cast(*Operands[0]); + if (FirstOperand.isToken() && FirstOperand.getToken() == "{") { + assert(Operands.size() == 1 && "Brackets should be by themselves"); + if (InBrackets) { + getParser().Error(IDLoc, "Already in a packet"); + return true; + } + InBrackets = true; + return false; + } + if (FirstOperand.isToken() && FirstOperand.getToken() == "}") { + assert(Operands.size() == 1 && "Brackets should be by themselves"); + if (!InBrackets) { + getParser().Error(IDLoc, "Not in a packet"); + return true; + } + InBrackets = false; + if (matchBundleOptions()) + return true; + return finishBundle(IDLoc, Out); + } + MCInst *SubInst = new (getParser().getContext()) MCInst; + bool MustExtend = false; + if (matchOneInstruction(*SubInst, IDLoc, Operands, ErrorInfo, + MatchingInlineAsm, MustExtend)) + return true; + HexagonMCInstrInfo::extendIfNeeded( + MCII, MCB, *SubInst, + HexagonMCInstrInfo::isExtended(MCII, *SubInst) || MustExtend); + MCB.addOperand(MCOperand::createInst(SubInst)); + if (!InBrackets) + return finishBundle(IDLoc, Out); + return false; +} + +/// ParseDirective parses the Hexagon specific directives +bool HexagonAsmParser::ParseDirective(AsmToken DirectiveID) { + StringRef IDVal = DirectiveID.getIdentifier(); + if ((IDVal.lower() == ".word") || (IDVal.lower() == ".4byte")) + return ParseDirectiveValue(4, DirectiveID.getLoc()); + if (IDVal.lower() == ".short" || IDVal.lower() == ".hword" || + IDVal.lower() == ".half") + return ParseDirectiveValue(2, DirectiveID.getLoc()); + if (IDVal.lower() == ".falign") + return ParseDirectiveFalign(256, DirectiveID.getLoc()); + if ((IDVal.lower() == ".lcomm") || (IDVal.lower() == ".lcommon")) + return ParseDirectiveComm(true, DirectiveID.getLoc()); + if ((IDVal.lower() == ".comm") || (IDVal.lower() == ".common")) + return ParseDirectiveComm(false, DirectiveID.getLoc()); + if (IDVal.lower() == ".subsection") + return ParseDirectiveSubsection(DirectiveID.getLoc()); + + return true; +} +bool HexagonAsmParser::ParseDirectiveSubsection(SMLoc L) { + const MCExpr *Subsection = 0; + int64_t Res; + + assert((getLexer().isNot(AsmToken::EndOfStatement)) && + "Invalid subsection directive"); + getParser().parseExpression(Subsection); + + if (!Subsection->evaluateAsAbsolute(Res)) + return Error(L, "Cannot evaluate subsection number"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + // 0-8192 is the hard-coded range in MCObjectStreamper.cpp, this keeps the + // negative subsections together and in the same order but at the opposite + // end of the section. Only legacy hexagon-gcc created assembly code + // used negative subsections. + if ((Res < 0) && (Res > -8193)) + Subsection = MCConstantExpr::create(8192 + Res, this->getContext()); + + getStreamer().SubSection(Subsection); + return false; +} + +/// ::= .falign [expression] +bool HexagonAsmParser::ParseDirectiveFalign(unsigned Size, SMLoc L) { + + int64_t MaxBytesToFill = 15; + + // if there is an arguement + if (getLexer().isNot(AsmToken::EndOfStatement)) { + const MCExpr *Value; + SMLoc ExprLoc = L; + + // Make sure we have a number (false is returned if expression is a number) + if (getParser().parseExpression(Value) == false) { + // Make sure this is a number that is in range + const MCConstantExpr *MCE = dyn_cast(Value); + uint64_t IntValue = MCE->getValue(); + if (!isUIntN(Size, IntValue) && !isIntN(Size, IntValue)) + return Error(ExprLoc, "literal value out of range (256) for falign"); + MaxBytesToFill = IntValue; + Lex(); + } else { + return Error(ExprLoc, "not a valid expression for falign directive"); + } + } + + getTargetStreamer().emitFAlign(16, MaxBytesToFill); + Lex(); + + return false; +} + +/// ::= .word [ expression (, expression)* ] +bool HexagonAsmParser::ParseDirectiveValue(unsigned Size, SMLoc L) { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + + for (;;) { + const MCExpr *Value; + SMLoc ExprLoc = L; + if (getParser().parseExpression(Value)) + return true; + + // Special case constant expressions to match code generator. + if (const MCConstantExpr *MCE = dyn_cast(Value)) { + assert(Size <= 8 && "Invalid size"); + uint64_t IntValue = MCE->getValue(); + if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue)) + return Error(ExprLoc, "literal value out of range for directive"); + getStreamer().EmitIntValue(IntValue, Size); + } else + getStreamer().EmitValue(Value, Size); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + // FIXME: Improve diagnostic. + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + +// This is largely a copy of AsmParser's ParseDirectiveComm extended to +// accept a 3rd argument, AccessAlignment which indicates the smallest +// memory access made to the symbol, expressed in bytes. If no +// AccessAlignment is specified it defaults to the Alignment Value. +// Hexagon's .lcomm: +// .lcomm Symbol, Length, Alignment, AccessAlignment +bool HexagonAsmParser::ParseDirectiveComm(bool IsLocal, SMLoc Loc) { + // FIXME: need better way to detect if AsmStreamer (upstream removed + // getKind()) + if (getStreamer().hasRawTextSupport()) + return true; // Only object file output requires special treatment. + + StringRef Name; + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + // Handle the identifier as the key symbol. + MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + int64_t Size; + SMLoc SizeLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Size)) + return true; + + int64_t ByteAlignment = 1; + SMLoc ByteAlignmentLoc; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + ByteAlignmentLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(ByteAlignment)) + return true; + if (!isPowerOf2_64(ByteAlignment)) + return Error(ByteAlignmentLoc, "alignment must be a power of 2"); + } + + int64_t AccessAlignment = 0; + if (getLexer().is(AsmToken::Comma)) { + // The optional access argument specifies the size of the smallest memory + // access to be made to the symbol, expressed in bytes. + SMLoc AccessAlignmentLoc; + Lex(); + AccessAlignmentLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(AccessAlignment)) + return true; + + if (!isPowerOf2_64(AccessAlignment)) + return Error(AccessAlignmentLoc, "access alignment must be a power of 2"); + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.comm' or '.lcomm' directive"); + + Lex(); + + // NOTE: a size of zero for a .comm should create a undefined symbol + // but a size of .lcomm creates a bss symbol of size zero. + if (Size < 0) + return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive size, can't " + "be less than zero"); + + // NOTE: The alignment in the directive is a power of 2 value, the assembler + // may internally end up wanting an alignment in bytes. + // FIXME: Diagnose overflow. + if (ByteAlignment < 0) + return Error(ByteAlignmentLoc, "invalid '.comm' or '.lcomm' directive " + "alignment, can't be less than zero"); + + if (!Sym->isUndefined()) + return Error(Loc, "invalid symbol redefinition"); + + HexagonMCELFStreamer &HexagonELFStreamer = + static_cast(getStreamer()); + if (IsLocal) { + HexagonELFStreamer.HexagonMCEmitLocalCommonSymbol(Sym, Size, ByteAlignment, + AccessAlignment); + return false; + } + + HexagonELFStreamer.HexagonMCEmitCommonSymbol(Sym, Size, ByteAlignment, + AccessAlignment); + return false; +} + +// validate register against architecture +bool HexagonAsmParser::RegisterMatchesArch(unsigned MatchNum) const { + return true; +} + +// extern "C" void LLVMInitializeHexagonAsmLexer(); + +/// Force static initialization. +extern "C" void LLVMInitializeHexagonAsmParser() { + RegisterMCAsmParser X(TheHexagonTarget); +} + +#define GET_MATCHER_IMPLEMENTATION +#define GET_REGISTER_MATCHER +#include "HexagonGenAsmMatcher.inc" + +namespace { +bool previousEqual(OperandVector &Operands, size_t Index, StringRef String) { + if (Index >= Operands.size()) + return false; + MCParsedAsmOperand &Operand = *Operands[Operands.size() - Index - 1]; + if (!Operand.isToken()) + return false; + return static_cast(Operand).getToken().equals_lower(String); +} +bool previousIsLoop(OperandVector &Operands, size_t Index) { + return previousEqual(Operands, Index, "loop0") || + previousEqual(Operands, Index, "loop1") || + previousEqual(Operands, Index, "sp1loop0") || + previousEqual(Operands, Index, "sp2loop0") || + previousEqual(Operands, Index, "sp3loop0"); +} +} + +bool HexagonAsmParser::splitIdentifier(OperandVector &Operands) { + AsmToken const &Token = getParser().getTok(); + StringRef String = Token.getString(); + SMLoc Loc = Token.getLoc(); + getLexer().Lex(); + do { + std::pair HeadTail = String.split('.'); + if (!HeadTail.first.empty()) + Operands.push_back(HexagonOperand::CreateToken(HeadTail.first, Loc)); + if (!HeadTail.second.empty()) + Operands.push_back(HexagonOperand::CreateToken( + String.substr(HeadTail.first.size(), 1), Loc)); + String = HeadTail.second; + } while (!String.empty()); + return false; +} + +bool HexagonAsmParser::parseOperand(OperandVector &Operands) { + unsigned Register; + SMLoc Begin; + SMLoc End; + MCAsmLexer &Lexer = getLexer(); + if (!ParseRegister(Register, Begin, End)) { + if (!ErrorMissingParenthesis) + switch (Register) { + default: + break; + case Hexagon::P0: + case Hexagon::P1: + case Hexagon::P2: + case Hexagon::P3: + if (previousEqual(Operands, 0, "if")) { + if (WarnMissingParenthesis) + Warning (Begin, "Missing parenthesis around predicate register"); + static char const *LParen = "("; + static char const *RParen = ")"; + Operands.push_back(HexagonOperand::CreateToken(LParen, Begin)); + Operands.push_back(HexagonOperand::CreateReg(Register, Begin, End)); + AsmToken MaybeDotNew = Lexer.getTok(); + if (MaybeDotNew.is(AsmToken::TokenKind::Identifier) && + MaybeDotNew.getString().equals_lower(".new")) + splitIdentifier(Operands); + Operands.push_back(HexagonOperand::CreateToken(RParen, Begin)); + return false; + } + if (previousEqual(Operands, 0, "!") && + previousEqual(Operands, 1, "if")) { + if (WarnMissingParenthesis) + Warning (Begin, "Missing parenthesis around predicate register"); + static char const *LParen = "("; + static char const *RParen = ")"; + Operands.insert(Operands.end () - 1, + HexagonOperand::CreateToken(LParen, Begin)); + Operands.push_back(HexagonOperand::CreateReg(Register, Begin, End)); + AsmToken MaybeDotNew = Lexer.getTok(); + if (MaybeDotNew.is(AsmToken::TokenKind::Identifier) && + MaybeDotNew.getString().equals_lower(".new")) + splitIdentifier(Operands); + Operands.push_back(HexagonOperand::CreateToken(RParen, Begin)); + return false; + } + break; + } + Operands.push_back(HexagonOperand::CreateReg( + Register, Begin, End)); + return false; + } + return splitIdentifier(Operands); +} + +bool HexagonAsmParser::isLabel(AsmToken &Token) { + MCAsmLexer &Lexer = getLexer(); + AsmToken const &Second = Lexer.getTok(); + AsmToken Third = Lexer.peekTok(); + StringRef String = Token.getString(); + if (Token.is(AsmToken::TokenKind::LCurly) || + Token.is(AsmToken::TokenKind::RCurly)) + return false; + if (!Token.is(AsmToken::TokenKind::Identifier)) + return true; + if (!MatchRegisterName(String.lower())) + return true; + assert(Second.is(AsmToken::Colon)); + StringRef Raw (String.data(), Third.getString().data() - String.data() + + Third.getString().size()); + std::string Collapsed = Raw; + Collapsed.erase(std::remove_if(Collapsed.begin(), Collapsed.end(), isspace), + Collapsed.end()); + StringRef Whole = Collapsed; + std::pair DotSplit = Whole.split('.'); + if (!MatchRegisterName(DotSplit.first.lower())) + return true; + return false; +} + +bool HexagonAsmParser::handleNoncontigiousRegister(bool Contigious, SMLoc &Loc) { + if (!Contigious && ErrorNoncontigiousRegister) { + Error(Loc, "Register name is not contigious"); + return true; + } + if (!Contigious && WarnNoncontigiousRegister) + Warning(Loc, "Register name is not contigious"); + return false; +} + +bool HexagonAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { + MCAsmLexer &Lexer = getLexer(); + StartLoc = getLexer().getLoc(); + SmallVector Lookahead; + StringRef RawString(Lexer.getTok().getString().data(), 0); + bool Again = Lexer.is(AsmToken::Identifier); + bool NeededWorkaround = false; + while (Again) { + AsmToken const &Token = Lexer.getTok(); + RawString = StringRef(RawString.data(), + Token.getString().data() - RawString.data () + + Token.getString().size()); + Lookahead.push_back(Token); + Lexer.Lex(); + bool Contigious = Lexer.getTok().getString().data() == + Lookahead.back().getString().data() + + Lookahead.back().getString().size(); + bool Type = Lexer.is(AsmToken::Identifier) || Lexer.is(AsmToken::Dot) || + Lexer.is(AsmToken::Integer) || Lexer.is(AsmToken::Real) || + Lexer.is(AsmToken::Colon); + bool Workaround = Lexer.is(AsmToken::Colon) || + Lookahead.back().is(AsmToken::Colon); + Again = (Contigious && Type) || (Workaround && Type); + NeededWorkaround = NeededWorkaround || (Again && !(Contigious && Type)); + } + std::string Collapsed = RawString; + Collapsed.erase(std::remove_if(Collapsed.begin(), Collapsed.end(), isspace), + Collapsed.end()); + StringRef FullString = Collapsed; + std::pair DotSplit = FullString.split('.'); + unsigned DotReg = MatchRegisterName(DotSplit.first.lower()); + if (DotReg != Hexagon::NoRegister && RegisterMatchesArch(DotReg)) { + if (DotSplit.second.empty()) { + RegNo = DotReg; + EndLoc = Lexer.getLoc(); + if (handleNoncontigiousRegister(!NeededWorkaround, StartLoc)) + return true; + return false; + } else { + RegNo = DotReg; + size_t First = RawString.find('.'); + StringRef DotString (RawString.data() + First, RawString.size() - First); + Lexer.UnLex(AsmToken(AsmToken::Identifier, DotString)); + EndLoc = Lexer.getLoc(); + if (handleNoncontigiousRegister(!NeededWorkaround, StartLoc)) + return true; + return false; + } + } + std::pair ColonSplit = StringRef(FullString).split(':'); + unsigned ColonReg = MatchRegisterName(ColonSplit.first.lower()); + if (ColonReg != Hexagon::NoRegister && RegisterMatchesArch(DotReg)) { + Lexer.UnLex(Lookahead.back()); + Lookahead.pop_back(); + Lexer.UnLex(Lookahead.back()); + Lookahead.pop_back(); + RegNo = ColonReg; + EndLoc = Lexer.getLoc(); + if (handleNoncontigiousRegister(!NeededWorkaround, StartLoc)) + return true; + return false; + } + while (!Lookahead.empty()) { + Lexer.UnLex(Lookahead.back()); + Lookahead.pop_back(); + } + return true; +} + +bool HexagonAsmParser::implicitExpressionLocation(OperandVector &Operands) { + if (previousEqual(Operands, 0, "call")) + return true; + if (previousEqual(Operands, 0, "jump")) + if (!getLexer().getTok().is(AsmToken::Colon)) + return true; + if (previousEqual(Operands, 0, "(") && previousIsLoop(Operands, 1)) + return true; + if (previousEqual(Operands, 1, ":") && previousEqual(Operands, 2, "jump") && + (previousEqual(Operands, 0, "nt") || previousEqual(Operands, 0, "t"))) + return true; + return false; +} + +bool HexagonAsmParser::parseExpression(MCExpr const *& Expr) { + llvm::SmallVector Tokens; + MCAsmLexer &Lexer = getLexer(); + bool Done = false; + static char const * Comma = ","; + do { + Tokens.emplace_back (Lexer.getTok()); + Lexer.Lex(); + switch (Tokens.back().getKind()) + { + case AsmToken::TokenKind::Hash: + if (Tokens.size () > 1) + if ((Tokens.end () - 2)->getKind() == AsmToken::TokenKind::Plus) { + Tokens.insert(Tokens.end() - 2, + AsmToken(AsmToken::TokenKind::Comma, Comma)); + Done = true; + } + break; + case AsmToken::TokenKind::RCurly: + case AsmToken::TokenKind::EndOfStatement: + case AsmToken::TokenKind::Eof: + Done = true; + break; + default: + break; + } + } while (!Done); + while (!Tokens.empty()) { + Lexer.UnLex(Tokens.back()); + Tokens.pop_back(); + } + return getParser().parseExpression(Expr); +} + +bool HexagonAsmParser::parseExpressionOrOperand(OperandVector &Operands) { + if (implicitExpressionLocation(Operands)) { + MCAsmParser &Parser = getParser(); + SMLoc Loc = Parser.getLexer().getLoc(); + std::unique_ptr Expr = + HexagonOperand::CreateImm(nullptr, Loc, Loc); + MCExpr const *& Val = Expr->Imm.Val; + Operands.push_back(std::move(Expr)); + return parseExpression(Val); + } + return parseOperand(Operands); +} + +/// Parse an instruction. +bool HexagonAsmParser::parseInstruction(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + MCAsmLexer &Lexer = getLexer(); + while (true) { + AsmToken const &Token = Parser.getTok(); + switch (Token.getKind()) { + case AsmToken::EndOfStatement: { + Lexer.Lex(); + return false; + } + case AsmToken::LCurly: { + if (!Operands.empty()) + return true; + Operands.push_back( + HexagonOperand::CreateToken(Token.getString(), Token.getLoc())); + Lexer.Lex(); + return false; + } + case AsmToken::RCurly: { + if (Operands.empty()) { + Operands.push_back( + HexagonOperand::CreateToken(Token.getString(), Token.getLoc())); + Lexer.Lex(); + } + return false; + } + case AsmToken::Comma: { + Lexer.Lex(); + continue; + } + case AsmToken::EqualEqual: + case AsmToken::ExclaimEqual: + case AsmToken::GreaterEqual: + case AsmToken::GreaterGreater: + case AsmToken::LessEqual: + case AsmToken::LessLess: { + Operands.push_back(HexagonOperand::CreateToken( + Token.getString().substr(0, 1), Token.getLoc())); + Operands.push_back(HexagonOperand::CreateToken( + Token.getString().substr(1, 1), Token.getLoc())); + Lexer.Lex(); + continue; + } + case AsmToken::Hash: { + bool MustNotExtend = false; + bool ImplicitExpression = implicitExpressionLocation(Operands); + std::unique_ptr Expr = HexagonOperand::CreateImm( + nullptr, Lexer.getLoc(), Lexer.getLoc()); + if (!ImplicitExpression) + Operands.push_back( + HexagonOperand::CreateToken(Token.getString(), Token.getLoc())); + Lexer.Lex(); + bool MustExtend = false; + bool HiOnly = false; + bool LoOnly = false; + if (Lexer.is(AsmToken::Hash)) { + Lexer.Lex(); + MustExtend = true; + } else if (ImplicitExpression) + MustNotExtend = true; + AsmToken const &Token = Parser.getTok(); + if (Token.is(AsmToken::Identifier)) { + StringRef String = Token.getString(); + AsmToken IDToken = Token; + if (String.lower() == "hi") { + HiOnly = true; + } else if (String.lower() == "lo") { + LoOnly = true; + } + if (HiOnly || LoOnly) { + AsmToken LParen = Lexer.peekTok(); + if (!LParen.is(AsmToken::LParen)) { + HiOnly = false; + LoOnly = false; + } else { + Lexer.Lex(); + } + } + } + if (parseExpression(Expr->Imm.Val)) + return true; + int64_t Value; + MCContext &Context = Parser.getContext(); + assert(Expr->Imm.Val != nullptr); + if (Expr->Imm.Val->evaluateAsAbsolute(Value)) { + if (HiOnly) + Expr->Imm.Val = MCBinaryExpr::createLShr( + Expr->Imm.Val, MCConstantExpr::create(16, Context), Context); + if (HiOnly || LoOnly) + Expr->Imm.Val = MCBinaryExpr::createAnd( + Expr->Imm.Val, MCConstantExpr::create(0xffff, Context), Context); + } + if (MustNotExtend) + Expr->Imm.Val = HexagonNoExtendOperand::Create(Expr->Imm.Val, Context); + Expr->Imm.MustExtend = MustExtend; + Operands.push_back(std::move(Expr)); + continue; + } + default: + break; + } + if (parseExpressionOrOperand(Operands)) + return true; + } +} + +bool HexagonAsmParser::ParseInstruction(ParseInstructionInfo &Info, + StringRef Name, + AsmToken ID, + OperandVector &Operands) { + getLexer().UnLex(ID); + return parseInstruction(Operands); +} + +namespace { +MCInst makeCombineInst(int opCode, MCOperand &Rdd, + MCOperand &MO1, MCOperand &MO2) { + MCInst TmpInst; + TmpInst.setOpcode(opCode); + TmpInst.addOperand(Rdd); + TmpInst.addOperand(MO1); + TmpInst.addOperand(MO2); + + return TmpInst; +} +} + +// Define this matcher function after the auto-generated include so we +// have the match class enum definitions. +unsigned HexagonAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, + unsigned Kind) { + HexagonOperand *Op = static_cast(&AsmOp); + + switch (Kind) { + case MCK_0: { + int64_t Value; + return Op->isImm() && Op->Imm.Val->evaluateAsAbsolute(Value) && Value == 0 + ? Match_Success + : Match_InvalidOperand; + } + case MCK_1: { + int64_t Value; + return Op->isImm() && Op->Imm.Val->evaluateAsAbsolute(Value) && Value == 1 + ? Match_Success + : Match_InvalidOperand; + } + case MCK__MINUS_1: { + int64_t Value; + return Op->isImm() && Op->Imm.Val->evaluateAsAbsolute(Value) && Value == -1 + ? Match_Success + : Match_InvalidOperand; + } + } + if (Op->Kind == HexagonOperand::Token && Kind != InvalidMatchClass) { + StringRef myStringRef = StringRef(Op->Tok.Data, Op->Tok.Length); + if (matchTokenString(myStringRef.lower()) == (MatchClassKind)Kind) + return Match_Success; + if (matchTokenString(myStringRef.upper()) == (MatchClassKind)Kind) + return Match_Success; + } + + DEBUG(dbgs() << "Unmatched Operand:"); + DEBUG(Op->dump()); + DEBUG(dbgs() << "\n"); + + return Match_InvalidOperand; +} + +void HexagonAsmParser::OutOfRange(SMLoc IDLoc, long long Val, long long Max) { + std::stringstream errStr; + errStr << "value " << Val << "(0x" << std::hex << Val << std::dec + << ") out of range: "; + if (Max >= 0) + errStr << "0-" << Max; + else + errStr << Max << "-" << (-Max - 1); + Error(IDLoc, errStr.str().c_str()); +} + +int HexagonAsmParser::processInstruction(MCInst &Inst, + OperandVector const &Operands, + SMLoc IDLoc, bool &MustExtend) { + MCContext &Context = getParser().getContext(); + const MCRegisterInfo *RI = getContext().getRegisterInfo(); + std::string r = "r"; + std::string v = "v"; + std::string Colon = ":"; + + bool is32bit = false; // used to distinguish between CONST32 and CONST64 + switch (Inst.getOpcode()) { + default: + break; + + case Hexagon::M4_mpyrr_addr: + case Hexagon::S4_addi_asl_ri: + case Hexagon::S4_addi_lsr_ri: + case Hexagon::S4_andi_asl_ri: + case Hexagon::S4_andi_lsr_ri: + case Hexagon::S4_ori_asl_ri: + case Hexagon::S4_ori_lsr_ri: + case Hexagon::S4_or_andix: + case Hexagon::S4_subi_asl_ri: + case Hexagon::S4_subi_lsr_ri: { + MCOperand &Ry = Inst.getOperand(0); + MCOperand &src = Inst.getOperand(2); + if (RI->getEncodingValue(Ry.getReg()) != RI->getEncodingValue(src.getReg())) + return Match_InvalidOperand; + break; + } + + case Hexagon::C2_cmpgei: { + MCOperand &MO = Inst.getOperand(2); + MO.setExpr(MCBinaryExpr::createSub( + MO.getExpr(), MCConstantExpr::create(1, Context), Context)); + Inst.setOpcode(Hexagon::C2_cmpgti); + break; + } + + case Hexagon::C2_cmpgeui: { + MCOperand &MO = Inst.getOperand(2); + int64_t Value; + bool Success = MO.getExpr()->evaluateAsAbsolute(Value); + assert(Success && "Assured by matcher"); + if (Value == 0) { + MCInst TmpInst; + MCOperand &Pd = Inst.getOperand(0); + MCOperand &Rt = Inst.getOperand(1); + TmpInst.setOpcode(Hexagon::C2_cmpeq); + TmpInst.addOperand(Pd); + TmpInst.addOperand(Rt); + TmpInst.addOperand(Rt); + Inst = TmpInst; + } else { + MO.setExpr(MCBinaryExpr::createSub( + MO.getExpr(), MCConstantExpr::create(1, Context), Context)); + Inst.setOpcode(Hexagon::C2_cmpgtui); + } + break; + } + case Hexagon::J2_loop1r: + case Hexagon::J2_loop1i: + case Hexagon::J2_loop0r: + case Hexagon::J2_loop0i: { + MCOperand &MO = Inst.getOperand(0); + // Loop has different opcodes for extended vs not extended, but we should + // not use the other opcode as it is a legacy artifact of TD files. + int64_t Value; + if (MO.getExpr()->evaluateAsAbsolute(Value)) { + // if the the operand can fit within a 7:2 field + if (Value < (1 << 8) && Value >= -(1 << 8)) { + SMLoc myLoc = Operands[2]->getStartLoc(); + // # is left in startLoc in the case of ## + // If '##' found then force extension. + if (*myLoc.getPointer() == '#') { + MustExtend = true; + break; + } + } else { + // If immediate and out of 7:2 range. + MustExtend = true; + } + } + break; + } + + // Translate a "$Rdd = $Rss" to "$Rdd = combine($Rs, $Rt)" + case Hexagon::A2_tfrp: { + MCOperand &MO = Inst.getOperand(1); + unsigned int RegPairNum = RI->getEncodingValue(MO.getReg()); + std::string R1 = r + llvm::utostr_32(RegPairNum + 1); + StringRef Reg1(R1); + MO.setReg(MatchRegisterName(Reg1)); + // Add a new operand for the second register in the pair. + std::string R2 = r + llvm::utostr_32(RegPairNum); + StringRef Reg2(R2); + Inst.addOperand(MCOperand::createReg(MatchRegisterName(Reg2))); + Inst.setOpcode(Hexagon::A2_combinew); + break; + } + + case Hexagon::A2_tfrpt: + case Hexagon::A2_tfrpf: { + MCOperand &MO = Inst.getOperand(2); + unsigned int RegPairNum = RI->getEncodingValue(MO.getReg()); + std::string R1 = r + llvm::utostr_32(RegPairNum + 1); + StringRef Reg1(R1); + MO.setReg(MatchRegisterName(Reg1)); + // Add a new operand for the second register in the pair. + std::string R2 = r + llvm::utostr_32(RegPairNum); + StringRef Reg2(R2); + Inst.addOperand(MCOperand::createReg(MatchRegisterName(Reg2))); + Inst.setOpcode((Inst.getOpcode() == Hexagon::A2_tfrpt) + ? Hexagon::C2_ccombinewt + : Hexagon::C2_ccombinewf); + break; + } + case Hexagon::A2_tfrptnew: + case Hexagon::A2_tfrpfnew: { + MCOperand &MO = Inst.getOperand(2); + unsigned int RegPairNum = RI->getEncodingValue(MO.getReg()); + std::string R1 = r + llvm::utostr_32(RegPairNum + 1); + StringRef Reg1(R1); + MO.setReg(MatchRegisterName(Reg1)); + // Add a new operand for the second register in the pair. + std::string R2 = r + llvm::utostr_32(RegPairNum); + StringRef Reg2(R2); + Inst.addOperand(MCOperand::createReg(MatchRegisterName(Reg2))); + Inst.setOpcode((Inst.getOpcode() == Hexagon::A2_tfrptnew) + ? Hexagon::C2_ccombinewnewt + : Hexagon::C2_ccombinewnewf); + break; + } + + // Translate a "$Rx = CONST32(#imm)" to "$Rx = memw(gp+#LABEL) " + case Hexagon::CONST32: + case Hexagon::CONST32_Float_Real: + case Hexagon::CONST32_Int_Real: + case Hexagon::FCONST32_nsdata: + is32bit = true; + // Translate a "$Rx:y = CONST64(#imm)" to "$Rx:y = memd(gp+#LABEL) " + case Hexagon::CONST64_Float_Real: + case Hexagon::CONST64_Int_Real: + + // FIXME: need better way to detect AsmStreamer (upstream removed getKind()) + if (!Parser.getStreamer().hasRawTextSupport()) { + MCELFStreamer *MES = static_cast(&Parser.getStreamer()); + MCOperand &MO_1 = Inst.getOperand(1); + MCOperand &MO_0 = Inst.getOperand(0); + + // push section onto section stack + MES->PushSection(); + + std::string myCharStr; + MCSectionELF *mySection; + + // check if this as an immediate or a symbol + int64_t Value; + bool Absolute = MO_1.getExpr()->evaluateAsAbsolute(Value); + if (Absolute) { + // Create a new section - one for each constant + // Some or all of the zeros are replaced with the given immediate. + if (is32bit) { + std::string myImmStr = utohexstr(static_cast(Value)); + myCharStr = StringRef(".gnu.linkonce.l4.CONST_00000000") + .drop_back(myImmStr.size()) + .str() + + myImmStr; + } else { + std::string myImmStr = utohexstr(Value); + myCharStr = StringRef(".gnu.linkonce.l8.CONST_0000000000000000") + .drop_back(myImmStr.size()) + .str() + + myImmStr; + } + + mySection = getContext().getELFSection(myCharStr, ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE); + } else if (MO_1.isExpr()) { + // .lita - for expressions + myCharStr = ".lita"; + mySection = getContext().getELFSection(myCharStr, ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE); + } else + llvm_unreachable("unexpected type of machine operand!"); + + MES->SwitchSection(mySection); + unsigned byteSize = is32bit ? 4 : 8; + getStreamer().EmitCodeAlignment(byteSize, byteSize); + + MCSymbol *Sym; + + // for symbols, get rid of prepended ".gnu.linkonce.lx." + + // emit symbol if needed + if (Absolute) { + Sym = getContext().getOrCreateSymbol(StringRef(myCharStr.c_str() + 16)); + if (Sym->isUndefined()) { + getStreamer().EmitLabel(Sym); + getStreamer().EmitSymbolAttribute(Sym, MCSA_Global); + getStreamer().EmitIntValue(Value, byteSize); + } + } else if (MO_1.isExpr()) { + const char *StringStart = 0; + const char *StringEnd = 0; + if (*Operands[4]->getStartLoc().getPointer() == '#') { + StringStart = Operands[5]->getStartLoc().getPointer(); + StringEnd = Operands[6]->getStartLoc().getPointer(); + } else { // no pound + StringStart = Operands[4]->getStartLoc().getPointer(); + StringEnd = Operands[5]->getStartLoc().getPointer(); + } + + unsigned size = StringEnd - StringStart; + std::string DotConst = ".CONST_"; + Sym = getContext().getOrCreateSymbol(DotConst + + StringRef(StringStart, size)); + + if (Sym->isUndefined()) { + // case where symbol is not yet defined: emit symbol + getStreamer().EmitLabel(Sym); + getStreamer().EmitSymbolAttribute(Sym, MCSA_Local); + getStreamer().EmitValue(MO_1.getExpr(), 4); + } + } else + llvm_unreachable("unexpected type of machine operand!"); + + MES->PopSection(); + + if (Sym) { + MCInst TmpInst; + if (is32bit) // 32 bit + TmpInst.setOpcode(Hexagon::L2_loadrigp); + else // 64 bit + TmpInst.setOpcode(Hexagon::L2_loadrdgp); + + TmpInst.addOperand(MO_0); + TmpInst.addOperand( + MCOperand::createExpr(MCSymbolRefExpr::create(Sym, getContext()))); + Inst = TmpInst; + } + } + break; + + // Translate a "$Rdd = #-imm" to "$Rdd = combine(#[-1,0], #-imm)" + case Hexagon::A2_tfrpi: { + MCOperand &Rdd = Inst.getOperand(0); + MCOperand &MO = Inst.getOperand(1); + int64_t Value; + int sVal = (MO.getExpr()->evaluateAsAbsolute(Value) && Value < 0) ? -1 : 0; + MCOperand imm(MCOperand::createExpr(MCConstantExpr::create(sVal, Context))); + Inst = makeCombineInst(Hexagon::A2_combineii, Rdd, imm, MO); + break; + } + + // Translate a "$Rdd = [#]#imm" to "$Rdd = combine(#, [#]#imm)" + case Hexagon::TFRI64_V4: { + MCOperand &Rdd = Inst.getOperand(0); + MCOperand &MO = Inst.getOperand(1); + int64_t Value; + if (MO.getExpr()->evaluateAsAbsolute(Value)) { + unsigned long long u64 = Value; + signed int s8 = (u64 >> 32) & 0xFFFFFFFF; + if (s8 < -128 || s8 > 127) + OutOfRange(IDLoc, s8, -128); + MCOperand imm(MCOperand::createExpr( + MCConstantExpr::create(s8, Context))); // upper 32 + MCOperand imm2(MCOperand::createExpr( + MCConstantExpr::create(u64 & 0xFFFFFFFF, Context))); // lower 32 + Inst = makeCombineInst(Hexagon::A4_combineii, Rdd, imm, imm2); + } else { + MCOperand imm(MCOperand::createExpr( + MCConstantExpr::create(0, Context))); // upper 32 + Inst = makeCombineInst(Hexagon::A4_combineii, Rdd, imm, MO); + } + break; + } + + // Handle $Rdd = combine(##imm, #imm)" + case Hexagon::TFRI64_V2_ext: { + MCOperand &Rdd = Inst.getOperand(0); + MCOperand &MO1 = Inst.getOperand(1); + MCOperand &MO2 = Inst.getOperand(2); + int64_t Value; + if (MO2.getExpr()->evaluateAsAbsolute(Value)) { + int s8 = Value; + if (s8 < -128 || s8 > 127) + OutOfRange(IDLoc, s8, -128); + } + Inst = makeCombineInst(Hexagon::A2_combineii, Rdd, MO1, MO2); + break; + } + + // Handle $Rdd = combine(#imm, ##imm)" + case Hexagon::A4_combineii: { + MCOperand &Rdd = Inst.getOperand(0); + MCOperand &MO1 = Inst.getOperand(1); + int64_t Value; + if (MO1.getExpr()->evaluateAsAbsolute(Value)) { + int s8 = Value; + if (s8 < -128 || s8 > 127) + OutOfRange(IDLoc, s8, -128); + } + MCOperand &MO2 = Inst.getOperand(2); + Inst = makeCombineInst(Hexagon::A4_combineii, Rdd, MO1, MO2); + break; + } + + case Hexagon::S2_tableidxb_goodsyntax: { + Inst.setOpcode(Hexagon::S2_tableidxb); + break; + } + + case Hexagon::S2_tableidxh_goodsyntax: { + MCInst TmpInst; + MCOperand &Rx = Inst.getOperand(0); + MCOperand &_dst_ = Inst.getOperand(1); + MCOperand &Rs = Inst.getOperand(2); + MCOperand &Imm4 = Inst.getOperand(3); + MCOperand &Imm6 = Inst.getOperand(4); + Imm6.setExpr(MCBinaryExpr::createSub( + Imm6.getExpr(), MCConstantExpr::create(1, Context), Context)); + TmpInst.setOpcode(Hexagon::S2_tableidxh); + TmpInst.addOperand(Rx); + TmpInst.addOperand(_dst_); + TmpInst.addOperand(Rs); + TmpInst.addOperand(Imm4); + TmpInst.addOperand(Imm6); + Inst = TmpInst; + break; + } + + case Hexagon::S2_tableidxw_goodsyntax: { + MCInst TmpInst; + MCOperand &Rx = Inst.getOperand(0); + MCOperand &_dst_ = Inst.getOperand(1); + MCOperand &Rs = Inst.getOperand(2); + MCOperand &Imm4 = Inst.getOperand(3); + MCOperand &Imm6 = Inst.getOperand(4); + Imm6.setExpr(MCBinaryExpr::createSub( + Imm6.getExpr(), MCConstantExpr::create(2, Context), Context)); + TmpInst.setOpcode(Hexagon::S2_tableidxw); + TmpInst.addOperand(Rx); + TmpInst.addOperand(_dst_); + TmpInst.addOperand(Rs); + TmpInst.addOperand(Imm4); + TmpInst.addOperand(Imm6); + Inst = TmpInst; + break; + } + + case Hexagon::S2_tableidxd_goodsyntax: { + MCInst TmpInst; + MCOperand &Rx = Inst.getOperand(0); + MCOperand &_dst_ = Inst.getOperand(1); + MCOperand &Rs = Inst.getOperand(2); + MCOperand &Imm4 = Inst.getOperand(3); + MCOperand &Imm6 = Inst.getOperand(4); + Imm6.setExpr(MCBinaryExpr::createSub( + Imm6.getExpr(), MCConstantExpr::create(3, Context), Context)); + TmpInst.setOpcode(Hexagon::S2_tableidxd); + TmpInst.addOperand(Rx); + TmpInst.addOperand(_dst_); + TmpInst.addOperand(Rs); + TmpInst.addOperand(Imm4); + TmpInst.addOperand(Imm6); + Inst = TmpInst; + break; + } + + case Hexagon::M2_mpyui: { + Inst.setOpcode(Hexagon::M2_mpyi); + break; + } + case Hexagon::M2_mpysmi: { + MCInst TmpInst; + MCOperand &Rd = Inst.getOperand(0); + MCOperand &Rs = Inst.getOperand(1); + MCOperand &Imm = Inst.getOperand(2); + int64_t Value; + bool Absolute = Imm.getExpr()->evaluateAsAbsolute(Value); + assert(Absolute); + (void)Absolute; + if (!MustExtend) { + if (Value < 0 && Value > -256) { + Imm.setExpr(MCConstantExpr::create(Value * -1, Context)); + TmpInst.setOpcode(Hexagon::M2_mpysin); + } else if (Value < 256 && Value >= 0) + TmpInst.setOpcode(Hexagon::M2_mpysip); + else + return Match_InvalidOperand; + } else { + if (Value >= 0) + TmpInst.setOpcode(Hexagon::M2_mpysip); + else + return Match_InvalidOperand; + } + TmpInst.addOperand(Rd); + TmpInst.addOperand(Rs); + TmpInst.addOperand(Imm); + Inst = TmpInst; + break; + } + + case Hexagon::S2_asr_i_r_rnd_goodsyntax: { + MCOperand &Imm = Inst.getOperand(2); + MCInst TmpInst; + int64_t Value; + bool Absolute = Imm.getExpr()->evaluateAsAbsolute(Value); + assert(Absolute); + (void)Absolute; + if (Value == 0) { // convert to $Rd = $Rs + TmpInst.setOpcode(Hexagon::A2_tfr); + MCOperand &Rd = Inst.getOperand(0); + MCOperand &Rs = Inst.getOperand(1); + TmpInst.addOperand(Rd); + TmpInst.addOperand(Rs); + } else { + Imm.setExpr(MCBinaryExpr::createSub( + Imm.getExpr(), MCConstantExpr::create(1, Context), Context)); + TmpInst.setOpcode(Hexagon::S2_asr_i_r_rnd); + MCOperand &Rd = Inst.getOperand(0); + MCOperand &Rs = Inst.getOperand(1); + TmpInst.addOperand(Rd); + TmpInst.addOperand(Rs); + TmpInst.addOperand(Imm); + } + Inst = TmpInst; + break; + } + + case Hexagon::S2_asr_i_p_rnd_goodsyntax: { + MCOperand &Rdd = Inst.getOperand(0); + MCOperand &Rss = Inst.getOperand(1); + MCOperand &Imm = Inst.getOperand(2); + int64_t Value; + bool Absolute = Imm.getExpr()->evaluateAsAbsolute(Value); + assert(Absolute); + (void)Absolute; + if (Value == 0) { // convert to $Rdd = combine ($Rs[0], $Rs[1]) + MCInst TmpInst; + unsigned int RegPairNum = RI->getEncodingValue(Rss.getReg()); + std::string R1 = r + llvm::utostr_32(RegPairNum + 1); + StringRef Reg1(R1); + Rss.setReg(MatchRegisterName(Reg1)); + // Add a new operand for the second register in the pair. + std::string R2 = r + llvm::utostr_32(RegPairNum); + StringRef Reg2(R2); + TmpInst.setOpcode(Hexagon::A2_combinew); + TmpInst.addOperand(Rdd); + TmpInst.addOperand(Rss); + TmpInst.addOperand(MCOperand::createReg(MatchRegisterName(Reg2))); + Inst = TmpInst; + } else { + Imm.setExpr(MCBinaryExpr::createSub( + Imm.getExpr(), MCConstantExpr::create(1, Context), Context)); + Inst.setOpcode(Hexagon::S2_asr_i_p_rnd); + } + break; + } + + case Hexagon::A4_boundscheck: { + MCOperand &Rs = Inst.getOperand(1); + unsigned int RegNum = RI->getEncodingValue(Rs.getReg()); + if (RegNum & 1) { // Odd mapped to raw:hi, regpair is rodd:odd-1, like r3:2 + Inst.setOpcode(Hexagon::A4_boundscheck_hi); + std::string Name = + r + llvm::utostr_32(RegNum) + Colon + llvm::utostr_32(RegNum - 1); + StringRef RegPair = Name; + Rs.setReg(MatchRegisterName(RegPair)); + } else { // raw:lo + Inst.setOpcode(Hexagon::A4_boundscheck_lo); + std::string Name = + r + llvm::utostr_32(RegNum + 1) + Colon + llvm::utostr_32(RegNum); + StringRef RegPair = Name; + Rs.setReg(MatchRegisterName(RegPair)); + } + break; + } + + case Hexagon::A2_addsp: { + MCOperand &Rs = Inst.getOperand(1); + unsigned int RegNum = RI->getEncodingValue(Rs.getReg()); + if (RegNum & 1) { // Odd mapped to raw:hi + Inst.setOpcode(Hexagon::A2_addsph); + std::string Name = + r + llvm::utostr_32(RegNum) + Colon + llvm::utostr_32(RegNum - 1); + StringRef RegPair = Name; + Rs.setReg(MatchRegisterName(RegPair)); + } else { // Even mapped raw:lo + Inst.setOpcode(Hexagon::A2_addspl); + std::string Name = + r + llvm::utostr_32(RegNum + 1) + Colon + llvm::utostr_32(RegNum); + StringRef RegPair = Name; + Rs.setReg(MatchRegisterName(RegPair)); + } + break; + } + + case Hexagon::M2_vrcmpys_s1: { + MCOperand &Rt = Inst.getOperand(2); + unsigned int RegNum = RI->getEncodingValue(Rt.getReg()); + if (RegNum & 1) { // Odd mapped to sat:raw:hi + Inst.setOpcode(Hexagon::M2_vrcmpys_s1_h); + std::string Name = + r + llvm::utostr_32(RegNum) + Colon + llvm::utostr_32(RegNum - 1); + StringRef RegPair = Name; + Rt.setReg(MatchRegisterName(RegPair)); + } else { // Even mapped sat:raw:lo + Inst.setOpcode(Hexagon::M2_vrcmpys_s1_l); + std::string Name = + r + llvm::utostr_32(RegNum + 1) + Colon + llvm::utostr_32(RegNum); + StringRef RegPair = Name; + Rt.setReg(MatchRegisterName(RegPair)); + } + break; + } + + case Hexagon::M2_vrcmpys_acc_s1: { + MCInst TmpInst; + MCOperand &Rxx = Inst.getOperand(0); + MCOperand &Rss = Inst.getOperand(2); + MCOperand &Rt = Inst.getOperand(3); + unsigned int RegNum = RI->getEncodingValue(Rt.getReg()); + if (RegNum & 1) { // Odd mapped to sat:raw:hi + TmpInst.setOpcode(Hexagon::M2_vrcmpys_acc_s1_h); + std::string Name = + r + llvm::utostr_32(RegNum) + Colon + llvm::utostr_32(RegNum - 1); + StringRef RegPair = Name; + Rt.setReg(MatchRegisterName(RegPair)); + } else { // Even mapped sat:raw:lo + TmpInst.setOpcode(Hexagon::M2_vrcmpys_acc_s1_l); + std::string Name = + r + llvm::utostr_32(RegNum + 1) + Colon + llvm::utostr_32(RegNum); + StringRef RegPair = Name; + Rt.setReg(MatchRegisterName(RegPair)); + } + // Registers are in different positions + TmpInst.addOperand(Rxx); + TmpInst.addOperand(Rxx); + TmpInst.addOperand(Rss); + TmpInst.addOperand(Rt); + Inst = TmpInst; + break; + } + + case Hexagon::M2_vrcmpys_s1rp: { + MCOperand &Rt = Inst.getOperand(2); + unsigned int RegNum = RI->getEncodingValue(Rt.getReg()); + if (RegNum & 1) { // Odd mapped to rnd:sat:raw:hi + Inst.setOpcode(Hexagon::M2_vrcmpys_s1rp_h); + std::string Name = + r + llvm::utostr_32(RegNum) + Colon + llvm::utostr_32(RegNum - 1); + StringRef RegPair = Name; + Rt.setReg(MatchRegisterName(RegPair)); + } else { // Even mapped rnd:sat:raw:lo + Inst.setOpcode(Hexagon::M2_vrcmpys_s1rp_l); + std::string Name = + r + llvm::utostr_32(RegNum + 1) + Colon + llvm::utostr_32(RegNum); + StringRef RegPair = Name; + Rt.setReg(MatchRegisterName(RegPair)); + } + break; + } + + case Hexagon::S5_asrhub_rnd_sat_goodsyntax: { + MCOperand &Imm = Inst.getOperand(2); + int64_t Value; + bool Absolute = Imm.getExpr()->evaluateAsAbsolute(Value); + assert(Absolute); + (void)Absolute; + if (Value == 0) + Inst.setOpcode(Hexagon::S2_vsathub); + else { + Imm.setExpr(MCBinaryExpr::createSub( + Imm.getExpr(), MCConstantExpr::create(1, Context), Context)); + Inst.setOpcode(Hexagon::S5_asrhub_rnd_sat); + } + break; + } + + case Hexagon::S5_vasrhrnd_goodsyntax: { + MCOperand &Rdd = Inst.getOperand(0); + MCOperand &Rss = Inst.getOperand(1); + MCOperand &Imm = Inst.getOperand(2); + int64_t Value; + bool Absolute = Imm.getExpr()->evaluateAsAbsolute(Value); + assert(Absolute); + (void)Absolute; + if (Value == 0) { + MCInst TmpInst; + unsigned int RegPairNum = RI->getEncodingValue(Rss.getReg()); + std::string R1 = r + llvm::utostr_32(RegPairNum + 1); + StringRef Reg1(R1); + Rss.setReg(MatchRegisterName(Reg1)); + // Add a new operand for the second register in the pair. + std::string R2 = r + llvm::utostr_32(RegPairNum); + StringRef Reg2(R2); + TmpInst.setOpcode(Hexagon::A2_combinew); + TmpInst.addOperand(Rdd); + TmpInst.addOperand(Rss); + TmpInst.addOperand(MCOperand::createReg(MatchRegisterName(Reg2))); + Inst = TmpInst; + } else { + Imm.setExpr(MCBinaryExpr::createSub( + Imm.getExpr(), MCConstantExpr::create(1, Context), Context)); + Inst.setOpcode(Hexagon::S5_vasrhrnd); + } + break; + } + + case Hexagon::A2_not: { + MCInst TmpInst; + MCOperand &Rd = Inst.getOperand(0); + MCOperand &Rs = Inst.getOperand(1); + TmpInst.setOpcode(Hexagon::A2_subri); + TmpInst.addOperand(Rd); + TmpInst.addOperand( + MCOperand::createExpr(MCConstantExpr::create(-1, Context))); + TmpInst.addOperand(Rs); + Inst = TmpInst; + break; + } + } // switch + + return Match_Success; +} diff --git a/lib/Target/Hexagon/AsmParser/LLVMBuild.txt b/lib/Target/Hexagon/AsmParser/LLVMBuild.txt new file mode 100644 index 00000000000..fdd875b6190 --- /dev/null +++ b/lib/Target/Hexagon/AsmParser/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/Hexagon/AsmParser/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 = HexagonAsmParser +parent = Hexagon +required_libraries = MC MCParser Support HexagonDesc HexagonInfo +add_to_library_groups = Hexagon diff --git a/lib/Target/Hexagon/AsmParser/Makefile b/lib/Target/Hexagon/AsmParser/Makefile new file mode 100644 index 00000000000..0aa0b4140c3 --- /dev/null +++ b/lib/Target/Hexagon/AsmParser/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/Hexagon/AsmParser/Makefile ------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMHexagonAsmParser + +# Hack: we need to include 'main' Hexagon target directory to grab private headers +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/Hexagon/CMakeLists.txt b/lib/Target/Hexagon/CMakeLists.txt index 3aa0c765cb5..181e4e3aa85 100644 --- a/lib/Target/Hexagon/CMakeLists.txt +++ b/lib/Target/Hexagon/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_TARGET_DEFINITIONS Hexagon.td) +tablegen(LLVM HexagonGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM HexagonGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM HexagonGenCallingConv.inc -gen-callingconv) tablegen(LLVM HexagonGenDAGISel.inc -gen-dag-isel) @@ -50,6 +51,7 @@ add_llvm_target(HexagonCodeGen HexagonVLIWPacketizer.cpp ) +add_subdirectory(AsmParser) add_subdirectory(TargetInfo) add_subdirectory(MCTargetDesc) add_subdirectory(Disassembler) diff --git a/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp b/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp index ef1887756ac..00e0c68c466 100644 --- a/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp +++ b/lib/Target/Hexagon/Disassembler/HexagonDisassembler.cpp @@ -7,42 +7,45 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "hexagon-disassembler" + #include "Hexagon.h" #include "MCTargetDesc/HexagonBaseInfo.h" -#include "MCTargetDesc/HexagonMCInstrInfo.h" +#include "MCTargetDesc/HexagonMCChecker.h" #include "MCTargetDesc/HexagonMCTargetDesc.h" - -#include "llvm/MC/MCContext.h" +#include "MCTargetDesc/HexagonMCInstrInfo.h" +#include "MCTargetDesc/HexagonInstPrinter.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixedLenDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" -#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/MemoryObject.h" #include "llvm/Support/raw_ostream.h" -#include +#include "llvm/Support/TargetRegistry.h" #include using namespace llvm; using namespace Hexagon; -#define DEBUG_TYPE "hexagon-disassembler" - -// Pull DecodeStatus and its enum values into the global namespace. -typedef llvm::MCDisassembler::DecodeStatus DecodeStatus; +typedef MCDisassembler::DecodeStatus DecodeStatus; namespace { /// \brief Hexagon disassembler for all Hexagon platforms. class HexagonDisassembler : public MCDisassembler { public: + std::unique_ptr const MCII; std::unique_ptr CurrentBundle; - HexagonDisassembler(MCSubtargetInfo const &STI, MCContext &Ctx) - : MCDisassembler(STI, Ctx), CurrentBundle(new MCInst *) {} + HexagonDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, + MCInstrInfo const *MCII) + : MCDisassembler(STI, Ctx), MCII(MCII), CurrentBundle(new MCInst *) {} DecodeStatus getSingleInstruction(MCInst &Instr, MCInst &MCB, ArrayRef Bytes, uint64_t Address, @@ -52,10 +55,16 @@ public: ArrayRef Bytes, uint64_t Address, raw_ostream &VStream, raw_ostream &CStream) const override; + + void adjustExtendedInstructions(MCInst &MCI, MCInst const &MCB) const; + void addSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) const; }; } -static DecodeStatus DecodeModRegsRegisterClass(MCInst &Inst, unsigned RegNo, +// Forward declare these because the auto-generated code will reference them. +// Definitions are further down. + +static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder); static DecodeStatus DecodeIntRegsLow8RegisterClass(MCInst &Inst, unsigned RegNo, @@ -64,23 +73,39 @@ static DecodeStatus DecodeIntRegsLow8RegisterClass(MCInst &Inst, unsigned RegNo, static DecodeStatus DecodeVectorRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeDoubleRegsRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder); static DecodeStatus DecodeVecDblRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder); +static DecodeStatus DecodePredRegsRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder); static DecodeStatus DecodeVecPredRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder); static DecodeStatus DecodeCtrRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeModRegsRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder); static DecodeStatus DecodeCtrRegs64RegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, - void const *Decoder); + const void *Decoder); + +static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn); +static DecodeStatus decodeImmext(MCInst &MI, uint32_t insn, + void const *Decoder); static unsigned GetSubinstOpcode(unsigned IClass, unsigned inst, unsigned &op, raw_ostream &os); -static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst); +static unsigned getRegFromSubinstEncoding(unsigned encoded_reg); + +static DecodeStatus unsignedImmDecoder(MCInst &MI, unsigned tmp, + uint64_t Address, const void *Decoder); static DecodeStatus s16ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address, const void *Decoder); static DecodeStatus s12ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address, @@ -111,129 +136,15 @@ static DecodeStatus s4_6ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address, const void *Decoder); static DecodeStatus s3_6ImmDecoder(MCInst &MI, unsigned tmp, uint64_t Address, const void *Decoder); - -static const uint16_t IntRegDecoderTable[] = { - Hexagon::R0, Hexagon::R1, Hexagon::R2, Hexagon::R3, Hexagon::R4, - Hexagon::R5, Hexagon::R6, Hexagon::R7, Hexagon::R8, Hexagon::R9, - Hexagon::R10, Hexagon::R11, Hexagon::R12, Hexagon::R13, Hexagon::R14, - Hexagon::R15, Hexagon::R16, Hexagon::R17, Hexagon::R18, Hexagon::R19, - Hexagon::R20, Hexagon::R21, Hexagon::R22, Hexagon::R23, Hexagon::R24, - Hexagon::R25, Hexagon::R26, Hexagon::R27, Hexagon::R28, Hexagon::R29, - Hexagon::R30, Hexagon::R31}; - -static const uint16_t PredRegDecoderTable[] = {Hexagon::P0, Hexagon::P1, - Hexagon::P2, Hexagon::P3}; - -static DecodeStatus DecodeRegisterClass(MCInst &Inst, unsigned RegNo, - const uint16_t Table[], size_t Size) { - if (RegNo < Size) { - Inst.addOperand(MCOperand::createReg(Table[RegNo])); - return MCDisassembler::Success; - } else - return MCDisassembler::Fail; -} - -static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, unsigned RegNo, - uint64_t /*Address*/, - void const *Decoder) { - if (RegNo > 31) - return MCDisassembler::Fail; - - unsigned Register = IntRegDecoderTable[RegNo]; - Inst.addOperand(MCOperand::createReg(Register)); - return MCDisassembler::Success; -} - -static DecodeStatus DecodeCtrRegsRegisterClass(MCInst &Inst, unsigned RegNo, - uint64_t /*Address*/, - const void *Decoder) { - static const uint16_t CtrlRegDecoderTable[] = { - Hexagon::SA0, Hexagon::LC0, Hexagon::SA1, Hexagon::LC1, - Hexagon::P3_0, Hexagon::NoRegister, Hexagon::C6, Hexagon::C7, - Hexagon::USR, Hexagon::PC, Hexagon::UGP, Hexagon::GP, - Hexagon::CS0, Hexagon::CS1, Hexagon::UPCL, Hexagon::UPCH}; - - if (RegNo >= sizeof(CtrlRegDecoderTable) / sizeof(CtrlRegDecoderTable[0])) - return MCDisassembler::Fail; - - if (CtrlRegDecoderTable[RegNo] == Hexagon::NoRegister) - return MCDisassembler::Fail; - - unsigned Register = CtrlRegDecoderTable[RegNo]; - Inst.addOperand(MCOperand::createReg(Register)); - return MCDisassembler::Success; -} - -static DecodeStatus DecodeCtrRegs64RegisterClass(MCInst &Inst, unsigned RegNo, - uint64_t /*Address*/, - void const *Decoder) { - static const uint16_t CtrlReg64DecoderTable[] = { - Hexagon::C1_0, Hexagon::NoRegister, Hexagon::C3_2, - Hexagon::NoRegister, Hexagon::NoRegister, Hexagon::NoRegister, - Hexagon::C7_6, Hexagon::NoRegister, Hexagon::C9_8, - Hexagon::NoRegister, Hexagon::C11_10, Hexagon::NoRegister, - Hexagon::CS, Hexagon::NoRegister, Hexagon::UPC, - Hexagon::NoRegister}; - - if (RegNo >= sizeof(CtrlReg64DecoderTable) / sizeof(CtrlReg64DecoderTable[0])) - return MCDisassembler::Fail; - - if (CtrlReg64DecoderTable[RegNo] == Hexagon::NoRegister) - return MCDisassembler::Fail; - - unsigned Register = CtrlReg64DecoderTable[RegNo]; - Inst.addOperand(MCOperand::createReg(Register)); - return MCDisassembler::Success; -} - -static DecodeStatus DecodeModRegsRegisterClass(MCInst &Inst, unsigned RegNo, - uint64_t /*Address*/, - const void *Decoder) { - unsigned Register = 0; - switch (RegNo) { - case 0: - Register = Hexagon::M0; - break; - case 1: - Register = Hexagon::M1; - break; - default: - return MCDisassembler::Fail; - } - Inst.addOperand(MCOperand::createReg(Register)); - return MCDisassembler::Success; -} - -static DecodeStatus DecodeDoubleRegsRegisterClass(MCInst &Inst, unsigned RegNo, - uint64_t /*Address*/, - const void *Decoder) { - static const uint16_t DoubleRegDecoderTable[] = { - Hexagon::D0, Hexagon::D1, Hexagon::D2, Hexagon::D3, - Hexagon::D4, Hexagon::D5, Hexagon::D6, Hexagon::D7, - Hexagon::D8, Hexagon::D9, Hexagon::D10, Hexagon::D11, - Hexagon::D12, Hexagon::D13, Hexagon::D14, Hexagon::D15}; - - return (DecodeRegisterClass(Inst, RegNo >> 1, DoubleRegDecoderTable, - sizeof(DoubleRegDecoderTable))); -} - -static DecodeStatus DecodePredRegsRegisterClass(MCInst &Inst, unsigned RegNo, - uint64_t /*Address*/, - void const *Decoder) { - if (RegNo > 3) - return MCDisassembler::Fail; - - unsigned Register = PredRegDecoderTable[RegNo]; - Inst.addOperand(MCOperand::createReg(Register)); - return MCDisassembler::Success; -} +static DecodeStatus brtargetDecoder(MCInst &MI, unsigned tmp, uint64_t Address, + const void *Decoder); #include "HexagonGenDisassemblerTables.inc" -static MCDisassembler *createHexagonDisassembler(Target const &T, - MCSubtargetInfo const &STI, +static MCDisassembler *createHexagonDisassembler(const Target &T, + const MCSubtargetInfo &STI, MCContext &Ctx) { - return new HexagonDisassembler(STI, Ctx); + return new HexagonDisassembler(STI, Ctx, T.createMCInstrInfo()); } extern "C" void LLVMInitializeHexagonDisassembler() { @@ -251,7 +162,6 @@ DecodeStatus HexagonDisassembler::getInstruction(MCInst &MI, uint64_t &Size, Size = 0; *CurrentBundle = &MI; - MI.clear(); MI.setOpcode(Hexagon::BUNDLE); MI.addOperand(MCOperand::createImm(0)); while (Result == Success && Complete == false) { @@ -263,7 +173,21 @@ DecodeStatus HexagonDisassembler::getInstruction(MCInst &MI, uint64_t &Size, Size += HEXAGON_INSTR_SIZE; Bytes = Bytes.slice(HEXAGON_INSTR_SIZE); } - return Result; + if(Result == MCDisassembler::Fail) + return Result; + HexagonMCChecker Checker (*MCII, STI, MI, MI, *getContext().getRegisterInfo()); + if(!Checker.check()) + return MCDisassembler::Fail; + return MCDisassembler::Success; +} + +namespace { +HexagonDisassembler const &disassembler(void const *Decoder) { + return *static_cast(Decoder); +} +MCContext &contextFromDecoder(void const *Decoder) { + return disassembler(Decoder).getContext(); +} } DecodeStatus HexagonDisassembler::getSingleInstruction( @@ -272,8 +196,7 @@ DecodeStatus HexagonDisassembler::getSingleInstruction( assert(Bytes.size() >= HEXAGON_INSTR_SIZE); uint32_t Instruction = - llvm::support::endian::read(Bytes.data()); + (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0); auto BundleSize = HexagonMCInstrInfo::bundleSize(MCB); if ((Instruction & HexagonII::INST_PARSE_MASK) == @@ -377,8 +300,8 @@ DecodeStatus HexagonDisassembler::getSingleInstruction( MILow->setOpcode(opLow); MCInst *MIHigh = new (getContext()) MCInst; MIHigh->setOpcode(opHigh); - AddSubinstOperands(MILow, opLow, instLow); - AddSubinstOperands(MIHigh, opHigh, instHigh); + addSubinstOperands(MILow, opLow, instLow); + addSubinstOperands(MIHigh, opHigh, instHigh); // see ConvertToSubInst() in // lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp @@ -395,16 +318,189 @@ DecodeStatus HexagonDisassembler::getSingleInstruction( // Calling the auto-generated decoder function. Result = decodeInstruction(DecoderTable32, MI, Instruction, Address, this, STI); + + // If a, "standard" insn isn't found check special cases. + if (MCDisassembler::Success != Result || + MI.getOpcode() == Hexagon::A4_ext) { + Result = decodeImmext(MI, Instruction, this); + if (MCDisassembler::Success != Result) { + Result = decodeSpecial(MI, Instruction); + } + } else { + // If the instruction is a compound instruction, register values will + // follow the duplex model, so the register values in the MCInst are + // incorrect. If the instruction is a compound, loop through the + // operands and change registers appropriately. + if (llvm::HexagonMCInstrInfo::getType(*MCII, MI) == + HexagonII::TypeCOMPOUND) { + for (MCInst::iterator i = MI.begin(), last = MI.end(); i < last; ++i) { + if (i->isReg()) { + unsigned reg = i->getReg() - Hexagon::R0; + i->setReg(getRegFromSubinstEncoding(reg)); + } + } + } + } + } + + if (HexagonMCInstrInfo::isNewValue(*MCII, MI)) { + unsigned OpIndex = HexagonMCInstrInfo::getNewValueOp(*MCII, MI); + MCOperand &MCO = MI.getOperand(OpIndex); + assert(MCO.isReg() && "New value consumers must be registers"); + unsigned Register = + getContext().getRegisterInfo()->getEncodingValue(MCO.getReg()); + if ((Register & 0x6) == 0) + // HexagonPRM 10.11 Bit 1-2 == 0 is reserved + return MCDisassembler::Fail; + unsigned Lookback = (Register & 0x6) >> 1; + unsigned Offset = 1; + bool Vector = HexagonMCInstrInfo::isVector(*MCII, MI); + auto Instructions = HexagonMCInstrInfo::bundleInstructions(**CurrentBundle); + auto i = Instructions.end() - 1; + for (auto n = Instructions.begin() - 1;; --i, ++Offset) { + if (i == n) + // Couldn't find producer + return MCDisassembler::Fail; + if (Vector && !HexagonMCInstrInfo::isVector(*MCII, *i->getInst())) + // Skip scalars when calculating distances for vectors + ++Lookback; + if (HexagonMCInstrInfo::isImmext(*i->getInst())) + ++Lookback; + if (Offset == Lookback) + break; + } + auto const &Inst = *i->getInst(); + bool SubregBit = (Register & 0x1) != 0; + if (SubregBit && HexagonMCInstrInfo::hasNewValue2(*MCII, Inst)) { + // If subreg bit is set we're selecting the second produced newvalue + unsigned Producer = + HexagonMCInstrInfo::getNewValueOperand2(*MCII, Inst).getReg(); + assert(Producer != Hexagon::NoRegister); + MCO.setReg(Producer); + } else if (HexagonMCInstrInfo::hasNewValue(*MCII, Inst)) { + unsigned Producer = + HexagonMCInstrInfo::getNewValueOperand(*MCII, Inst).getReg(); + if (Producer >= Hexagon::W0 && Producer <= Hexagon::W15) + Producer = ((Producer - Hexagon::W0) << 1) + SubregBit + Hexagon::V0; + else if (SubregBit) + // Subreg bit should not be set for non-doublevector newvalue producers + return MCDisassembler::Fail; + assert(Producer != Hexagon::NoRegister); + MCO.setReg(Producer); + } else + return MCDisassembler::Fail; } + adjustExtendedInstructions(MI, MCB); + MCInst const *Extender = + HexagonMCInstrInfo::extenderForIndex(MCB, + HexagonMCInstrInfo::bundleSize(MCB)); + if(Extender != nullptr) { + MCInst const & Inst = HexagonMCInstrInfo::isDuplex(*MCII, MI) ? + *MI.getOperand(1).getInst() : MI; + if (!HexagonMCInstrInfo::isExtendable(*MCII, Inst) && + !HexagonMCInstrInfo::isExtended(*MCII, Inst)) + return MCDisassembler::Fail; + } return Result; } + +void HexagonDisassembler::adjustExtendedInstructions(MCInst &MCI, + MCInst const &MCB) const { + if (!HexagonMCInstrInfo::hasExtenderForIndex( + MCB, HexagonMCInstrInfo::bundleSize(MCB))) { + unsigned opcode; + // This code is used by the disassembler to disambiguate between GP + // relative and absolute addressing instructions since they both have + // same encoding bits. However, an absolute addressing instruction must + // follow an immediate extender. Disassembler alwaus select absolute + // addressing instructions first and uses this code to change them into + // GP relative instruction in the absence of the corresponding immediate + // extender. + switch (MCI.getOpcode()) { + case Hexagon::S2_storerbabs: + opcode = Hexagon::S2_storerbgp; + break; + case Hexagon::S2_storerhabs: + opcode = Hexagon::S2_storerhgp; + break; + case Hexagon::S2_storerfabs: + opcode = Hexagon::S2_storerfgp; + break; + case Hexagon::S2_storeriabs: + opcode = Hexagon::S2_storerigp; + break; + case Hexagon::S2_storerbnewabs: + opcode = Hexagon::S2_storerbnewgp; + break; + case Hexagon::S2_storerhnewabs: + opcode = Hexagon::S2_storerhnewgp; + break; + case Hexagon::S2_storerinewabs: + opcode = Hexagon::S2_storerinewgp; + break; + case Hexagon::S2_storerdabs: + opcode = Hexagon::S2_storerdgp; + break; + case Hexagon::L4_loadrb_abs: + opcode = Hexagon::L2_loadrbgp; + break; + case Hexagon::L4_loadrub_abs: + opcode = Hexagon::L2_loadrubgp; + break; + case Hexagon::L4_loadrh_abs: + opcode = Hexagon::L2_loadrhgp; + break; + case Hexagon::L4_loadruh_abs: + opcode = Hexagon::L2_loadruhgp; + break; + case Hexagon::L4_loadri_abs: + opcode = Hexagon::L2_loadrigp; + break; + case Hexagon::L4_loadrd_abs: + opcode = Hexagon::L2_loadrdgp; + break; + default: + opcode = MCI.getOpcode(); + } + MCI.setOpcode(opcode); + } +} + +namespace llvm { +extern const MCInstrDesc HexagonInsts[]; +} + +static DecodeStatus DecodeRegisterClass(MCInst &Inst, unsigned RegNo, + const uint16_t Table[], size_t Size) { + if (RegNo < Size) { + Inst.addOperand(MCOperand::createReg(Table[RegNo])); + return MCDisassembler::Success; + } else + return MCDisassembler::Fail; +} + static DecodeStatus DecodeIntRegsLow8RegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder) { return DecodeIntRegsRegisterClass(Inst, RegNo, Address, Decoder); } +static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder) { + static const uint16_t IntRegDecoderTable[] = { + Hexagon::R0, Hexagon::R1, Hexagon::R2, Hexagon::R3, Hexagon::R4, + Hexagon::R5, Hexagon::R6, Hexagon::R7, Hexagon::R8, Hexagon::R9, + Hexagon::R10, Hexagon::R11, Hexagon::R12, Hexagon::R13, Hexagon::R14, + Hexagon::R15, Hexagon::R16, Hexagon::R17, Hexagon::R18, Hexagon::R19, + Hexagon::R20, Hexagon::R21, Hexagon::R22, Hexagon::R23, Hexagon::R24, + Hexagon::R25, Hexagon::R26, Hexagon::R27, Hexagon::R28, Hexagon::R29, + Hexagon::R30, Hexagon::R31}; + + return (DecodeRegisterClass(Inst, RegNo, IntRegDecoderTable, + sizeof(IntRegDecoderTable))); +} static DecodeStatus DecodeVectorRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t /*Address*/, @@ -422,6 +518,19 @@ static DecodeStatus DecodeVectorRegsRegisterClass(MCInst &Inst, unsigned RegNo, sizeof(VecRegDecoderTable))); } +static DecodeStatus DecodeDoubleRegsRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t /*Address*/, + const void *Decoder) { + static const uint16_t DoubleRegDecoderTable[] = { + Hexagon::D0, Hexagon::D1, Hexagon::D2, Hexagon::D3, + Hexagon::D4, Hexagon::D5, Hexagon::D6, Hexagon::D7, + Hexagon::D8, Hexagon::D9, Hexagon::D10, Hexagon::D11, + Hexagon::D12, Hexagon::D13, Hexagon::D14, Hexagon::D15}; + + return (DecodeRegisterClass(Inst, RegNo >> 1, DoubleRegDecoderTable, + sizeof(DoubleRegDecoderTable))); +} + static DecodeStatus DecodeVecDblRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t /*Address*/, const void *Decoder) { @@ -435,6 +544,16 @@ static DecodeStatus DecodeVecDblRegsRegisterClass(MCInst &Inst, unsigned RegNo, sizeof(VecDblRegDecoderTable))); } +static DecodeStatus DecodePredRegsRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t /*Address*/, + const void *Decoder) { + static const uint16_t PredRegDecoderTable[] = {Hexagon::P0, Hexagon::P1, + Hexagon::P2, Hexagon::P3}; + + return (DecodeRegisterClass(Inst, RegNo, PredRegDecoderTable, + sizeof(PredRegDecoderTable))); +} + static DecodeStatus DecodeVecPredRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t /*Address*/, const void *Decoder) { @@ -445,111 +564,535 @@ static DecodeStatus DecodeVecPredRegsRegisterClass(MCInst &Inst, unsigned RegNo, sizeof(VecPredRegDecoderTable))); } +static DecodeStatus DecodeCtrRegsRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t /*Address*/, + const void *Decoder) { + static const uint16_t CtrlRegDecoderTable[] = { + Hexagon::SA0, Hexagon::LC0, Hexagon::SA1, Hexagon::LC1, + Hexagon::P3_0, Hexagon::C5, Hexagon::C6, Hexagon::C7, + Hexagon::USR, Hexagon::PC, Hexagon::UGP, Hexagon::GP, + Hexagon::CS0, Hexagon::CS1, Hexagon::UPCL, Hexagon::UPC + }; + + if (RegNo >= sizeof(CtrlRegDecoderTable) / sizeof(CtrlRegDecoderTable[0])) + return MCDisassembler::Fail; + + if (CtrlRegDecoderTable[RegNo] == Hexagon::NoRegister) + return MCDisassembler::Fail; + + unsigned Register = CtrlRegDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Register)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeCtrRegs64RegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t /*Address*/, + const void *Decoder) { + static const uint16_t CtrlReg64DecoderTable[] = { + Hexagon::C1_0, Hexagon::NoRegister, + Hexagon::C3_2, Hexagon::NoRegister, + Hexagon::C7_6, Hexagon::NoRegister, + Hexagon::C9_8, Hexagon::NoRegister, + Hexagon::C11_10, Hexagon::NoRegister, + Hexagon::CS, Hexagon::NoRegister, + Hexagon::UPC, Hexagon::NoRegister + }; + + if (RegNo >= sizeof(CtrlReg64DecoderTable) / sizeof(CtrlReg64DecoderTable[0])) + return MCDisassembler::Fail; + + if (CtrlReg64DecoderTable[RegNo] == Hexagon::NoRegister) + return MCDisassembler::Fail; + + unsigned Register = CtrlReg64DecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Register)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeModRegsRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t /*Address*/, + const void *Decoder) { + unsigned Register = 0; + switch (RegNo) { + case 0: + Register = Hexagon::M0; + break; + case 1: + Register = Hexagon::M1; + break; + default: + return MCDisassembler::Fail; + } + Inst.addOperand(MCOperand::createReg(Register)); + return MCDisassembler::Success; +} + +namespace { +uint32_t fullValue(MCInstrInfo const &MCII, + MCInst &MCB, + MCInst &MI, + int64_t Value) { + MCInst const *Extender = HexagonMCInstrInfo::extenderForIndex( + MCB, HexagonMCInstrInfo::bundleSize(MCB)); + if(!Extender || MI.size() != HexagonMCInstrInfo::getExtendableOp(MCII, MI)) + return Value; + unsigned Alignment = HexagonMCInstrInfo::getExtentAlignment(MCII, MI); + uint32_t Lower6 = static_cast(Value >> Alignment) & 0x3f; + int64_t Bits; + bool Success = Extender->getOperand(0).getExpr()->evaluateAsAbsolute(Bits); + assert(Success);(void)Success; + uint32_t Upper26 = static_cast(Bits); + uint32_t Operand = Upper26 | Lower6; + return Operand; +} +template +void signedDecoder(MCInst &MI, unsigned tmp, const void *Decoder) { + HexagonDisassembler const &Disassembler = disassembler(Decoder); + int64_t FullValue = fullValue(*Disassembler.MCII, + **Disassembler.CurrentBundle, + MI, SignExtend64(tmp)); + int64_t Extended = SignExtend64<32>(FullValue); + HexagonMCInstrInfo::addConstant(MI, Extended, + Disassembler.getContext()); +} +} + +static DecodeStatus unsignedImmDecoder(MCInst &MI, unsigned tmp, + uint64_t /*Address*/, + const void *Decoder) { + HexagonDisassembler const &Disassembler = disassembler(Decoder); + int64_t FullValue = fullValue(*Disassembler.MCII, + **Disassembler.CurrentBundle, + MI, tmp); + assert(FullValue >= 0 && "Negative in unsigned decoder"); + HexagonMCInstrInfo::addConstant(MI, FullValue, Disassembler.getContext()); + return MCDisassembler::Success; +} + static DecodeStatus s16ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<16>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<16>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s12ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<12>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<12>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s11_0ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<11>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<11>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s11_1ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<12>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + HexagonMCInstrInfo::addConstant(MI, SignExtend64<12>(tmp), contextFromDecoder(Decoder)); return MCDisassembler::Success; } static DecodeStatus s11_2ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<13>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<13>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s11_3ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<14>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<14>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s10ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<10>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<10>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s8ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<8>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<8>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s6_0ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<6>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<6>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s4_0ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<4>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<4>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s4_1ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<5>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<5>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s4_2ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<6>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<6>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s4_3ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<7>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<7>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s4_6ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<10>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<10>(MI, tmp, Decoder); return MCDisassembler::Success; } static DecodeStatus s3_6ImmDecoder(MCInst &MI, unsigned tmp, uint64_t /*Address*/, const void *Decoder) { - uint64_t imm = SignExtend64<9>(tmp); - MI.addOperand(MCOperand::createImm(imm)); + signedDecoder<19>(MI, tmp, Decoder); + return MCDisassembler::Success; +} + +// custom decoder for various jump/call immediates +static DecodeStatus brtargetDecoder(MCInst &MI, unsigned tmp, uint64_t Address, + const void *Decoder) { + HexagonDisassembler const &Disassembler = disassembler(Decoder); + unsigned Bits = HexagonMCInstrInfo::getExtentBits(*Disassembler.MCII, MI); + // r13_2 is not extendable, so if there are no extent bits, it's r13_2 + if (Bits == 0) + Bits = 15; + uint32_t FullValue = fullValue(*Disassembler.MCII, + **Disassembler.CurrentBundle, + MI, SignExtend64(tmp, Bits)); + int64_t Extended = SignExtend64<32>(FullValue) + Address; + if (!Disassembler.tryAddingSymbolicOperand(MI, Extended, Address, true, + 0, 4)) + HexagonMCInstrInfo::addConstant(MI, Extended, Disassembler.getContext()); return MCDisassembler::Success; } +// Addressing mode dependent load store opcode map. +// - If an insn is preceded by an extender the address is absolute. +// - memw(##symbol) = r0 +// - If an insn is not preceded by an extender the address is GP relative. +// - memw(gp + #symbol) = r0 +// Please note that the instructions must be ordered in the descending order +// of their opcode. +// HexagonII::INST_ICLASS_ST +static unsigned int StoreConditionalOpcodeData[][2] = { + {S4_pstorerdfnew_abs, 0xafc02084}, + {S4_pstorerdtnew_abs, 0xafc02080}, + {S4_pstorerdf_abs, 0xafc00084}, + {S4_pstorerdt_abs, 0xafc00080}, + {S4_pstorerinewfnew_abs, 0xafa03084}, + {S4_pstorerinewtnew_abs, 0xafa03080}, + {S4_pstorerhnewfnew_abs, 0xafa02884}, + {S4_pstorerhnewtnew_abs, 0xafa02880}, + {S4_pstorerbnewfnew_abs, 0xafa02084}, + {S4_pstorerbnewtnew_abs, 0xafa02080}, + {S4_pstorerinewf_abs, 0xafa01084}, + {S4_pstorerinewt_abs, 0xafa01080}, + {S4_pstorerhnewf_abs, 0xafa00884}, + {S4_pstorerhnewt_abs, 0xafa00880}, + {S4_pstorerbnewf_abs, 0xafa00084}, + {S4_pstorerbnewt_abs, 0xafa00080}, + {S4_pstorerifnew_abs, 0xaf802084}, + {S4_pstoreritnew_abs, 0xaf802080}, + {S4_pstorerif_abs, 0xaf800084}, + {S4_pstorerit_abs, 0xaf800080}, + {S4_pstorerhfnew_abs, 0xaf402084}, + {S4_pstorerhtnew_abs, 0xaf402080}, + {S4_pstorerhf_abs, 0xaf400084}, + {S4_pstorerht_abs, 0xaf400080}, + {S4_pstorerbfnew_abs, 0xaf002084}, + {S4_pstorerbtnew_abs, 0xaf002080}, + {S4_pstorerbf_abs, 0xaf000084}, + {S4_pstorerbt_abs, 0xaf000080}}; +// HexagonII::INST_ICLASS_LD + +// HexagonII::INST_ICLASS_LD_ST_2 +static unsigned int LoadStoreOpcodeData[][2] = {{L4_loadrd_abs, 0x49c00000}, + {L4_loadri_abs, 0x49800000}, + {L4_loadruh_abs, 0x49600000}, + {L4_loadrh_abs, 0x49400000}, + {L4_loadrub_abs, 0x49200000}, + {L4_loadrb_abs, 0x49000000}, + {S2_storerdabs, 0x48c00000}, + {S2_storerinewabs, 0x48a01000}, + {S2_storerhnewabs, 0x48a00800}, + {S2_storerbnewabs, 0x48a00000}, + {S2_storeriabs, 0x48800000}, + {S2_storerfabs, 0x48600000}, + {S2_storerhabs, 0x48400000}, + {S2_storerbabs, 0x48000000}}; +static int NumCondS = + sizeof(StoreConditionalOpcodeData) / sizeof(StoreConditionalOpcodeData[0]); +static int NumLS = sizeof(LoadStoreOpcodeData) / sizeof(LoadStoreOpcodeData[0]); + +static DecodeStatus decodeSpecial(MCInst &MI, uint32_t insn) { + + unsigned MachineOpcode = 0; + unsigned LLVMOpcode = 0; + int i; + + if ((insn & HexagonII::INST_ICLASS_MASK) == HexagonII::INST_ICLASS_ST) { + for (i = 0; i < NumCondS; ++i) { + if ((insn & StoreConditionalOpcodeData[i][1]) == + StoreConditionalOpcodeData[i][1]) { + MachineOpcode = StoreConditionalOpcodeData[i][1]; + LLVMOpcode = StoreConditionalOpcodeData[i][0]; + break; + } + } + } + if ((insn & HexagonII::INST_ICLASS_MASK) == HexagonII::INST_ICLASS_LD_ST_2) { + for (i = 0; i < NumLS; ++i) { + if ((insn & LoadStoreOpcodeData[i][1]) == LoadStoreOpcodeData[i][1]) { + MachineOpcode = LoadStoreOpcodeData[i][1]; + LLVMOpcode = LoadStoreOpcodeData[i][0]; + break; + } + } + } + + if (MachineOpcode) { + unsigned Value = 0; + unsigned shift = 0; + MI.setOpcode(LLVMOpcode); + // Remove the parse bits from the insn. + insn &= ~HexagonII::INST_PARSE_MASK; + + switch (LLVMOpcode) { + default: + return MCDisassembler::Fail; + break; + + case Hexagon::S4_pstorerdf_abs: + case Hexagon::S4_pstorerdt_abs: + case Hexagon::S4_pstorerdfnew_abs: + case Hexagon::S4_pstorerdtnew_abs: { + // op: Pv + Value = insn & UINT64_C(3); + DecodePredRegsRegisterClass(MI, Value, 0, 0); + // op: u6 + Value = (insn >> 12) & UINT64_C(48); + Value |= (insn >> 3) & UINT64_C(15); + MI.addOperand(MCOperand::createImm(Value)); + // op: Rtt + Value = (insn >> 8) & UINT64_C(31); + DecodeDoubleRegsRegisterClass(MI, Value, 0, 0); + break; + } + + case Hexagon::S4_pstorerbnewf_abs: + case Hexagon::S4_pstorerbnewt_abs: + case Hexagon::S4_pstorerbnewfnew_abs: + case Hexagon::S4_pstorerbnewtnew_abs: + case Hexagon::S4_pstorerhnewf_abs: + case Hexagon::S4_pstorerhnewt_abs: + case Hexagon::S4_pstorerhnewfnew_abs: + case Hexagon::S4_pstorerhnewtnew_abs: + case Hexagon::S4_pstorerinewf_abs: + case Hexagon::S4_pstorerinewt_abs: + case Hexagon::S4_pstorerinewfnew_abs: + case Hexagon::S4_pstorerinewtnew_abs: { + // op: Pv + Value = insn & UINT64_C(3); + DecodePredRegsRegisterClass(MI, Value, 0, 0); + // op: u6 + Value = (insn >> 12) & UINT64_C(48); + Value |= (insn >> 3) & UINT64_C(15); + MI.addOperand(MCOperand::createImm(Value)); + // op: Nt + Value = (insn >> 8) & UINT64_C(7); + DecodeIntRegsRegisterClass(MI, Value, 0, 0); + break; + } + + case Hexagon::S4_pstorerbf_abs: + case Hexagon::S4_pstorerbt_abs: + case Hexagon::S4_pstorerbfnew_abs: + case Hexagon::S4_pstorerbtnew_abs: + case Hexagon::S4_pstorerhf_abs: + case Hexagon::S4_pstorerht_abs: + case Hexagon::S4_pstorerhfnew_abs: + case Hexagon::S4_pstorerhtnew_abs: + case Hexagon::S4_pstorerif_abs: + case Hexagon::S4_pstorerit_abs: + case Hexagon::S4_pstorerifnew_abs: + case Hexagon::S4_pstoreritnew_abs: { + // op: Pv + Value = insn & UINT64_C(3); + DecodePredRegsRegisterClass(MI, Value, 0, 0); + // op: u6 + Value = (insn >> 12) & UINT64_C(48); + Value |= (insn >> 3) & UINT64_C(15); + MI.addOperand(MCOperand::createImm(Value)); + // op: Rt + Value = (insn >> 8) & UINT64_C(31); + DecodeIntRegsRegisterClass(MI, Value, 0, 0); + break; + } + + case Hexagon::L4_ploadrdf_abs: + case Hexagon::L4_ploadrdt_abs: + case Hexagon::L4_ploadrdfnew_abs: + case Hexagon::L4_ploadrdtnew_abs: { + // op: Rdd + Value = insn & UINT64_C(31); + DecodeDoubleRegsRegisterClass(MI, Value, 0, 0); + // op: Pt + Value = ((insn >> 9) & UINT64_C(3)); + DecodePredRegsRegisterClass(MI, Value, 0, 0); + // op: u6 + Value = ((insn >> 15) & UINT64_C(62)); + Value |= ((insn >> 8) & UINT64_C(1)); + MI.addOperand(MCOperand::createImm(Value)); + break; + } + + case Hexagon::L4_ploadrbf_abs: + case Hexagon::L4_ploadrbt_abs: + case Hexagon::L4_ploadrbfnew_abs: + case Hexagon::L4_ploadrbtnew_abs: + case Hexagon::L4_ploadrhf_abs: + case Hexagon::L4_ploadrht_abs: + case Hexagon::L4_ploadrhfnew_abs: + case Hexagon::L4_ploadrhtnew_abs: + case Hexagon::L4_ploadrubf_abs: + case Hexagon::L4_ploadrubt_abs: + case Hexagon::L4_ploadrubfnew_abs: + case Hexagon::L4_ploadrubtnew_abs: + case Hexagon::L4_ploadruhf_abs: + case Hexagon::L4_ploadruht_abs: + case Hexagon::L4_ploadruhfnew_abs: + case Hexagon::L4_ploadruhtnew_abs: + case Hexagon::L4_ploadrif_abs: + case Hexagon::L4_ploadrit_abs: + case Hexagon::L4_ploadrifnew_abs: + case Hexagon::L4_ploadritnew_abs: + // op: Rd + Value = insn & UINT64_C(31); + DecodeIntRegsRegisterClass(MI, Value, 0, 0); + // op: Pt + Value = (insn >> 9) & UINT64_C(3); + DecodePredRegsRegisterClass(MI, Value, 0, 0); + // op: u6 + Value = (insn >> 15) & UINT64_C(62); + Value |= (insn >> 8) & UINT64_C(1); + MI.addOperand(MCOperand::createImm(Value)); + break; + + // op: g16_2 + case (Hexagon::L4_loadri_abs): + ++shift; + // op: g16_1 + case Hexagon::L4_loadrh_abs: + case Hexagon::L4_loadruh_abs: + ++shift; + // op: g16_0 + case Hexagon::L4_loadrb_abs: + case Hexagon::L4_loadrub_abs: { + // op: Rd + Value |= insn & UINT64_C(31); + DecodeIntRegsRegisterClass(MI, Value, 0, 0); + Value = (insn >> 11) & UINT64_C(49152); + Value |= (insn >> 7) & UINT64_C(15872); + Value |= (insn >> 5) & UINT64_C(511); + MI.addOperand(MCOperand::createImm(Value << shift)); + break; + } + + case Hexagon::L4_loadrd_abs: { + Value = insn & UINT64_C(31); + DecodeDoubleRegsRegisterClass(MI, Value, 0, 0); + Value = (insn >> 11) & UINT64_C(49152); + Value |= (insn >> 7) & UINT64_C(15872); + Value |= (insn >> 5) & UINT64_C(511); + MI.addOperand(MCOperand::createImm(Value << 3)); + break; + } + + case Hexagon::S2_storerdabs: { + // op: g16_3 + Value = (insn >> 11) & UINT64_C(49152); + Value |= (insn >> 7) & UINT64_C(15872); + Value |= (insn >> 5) & UINT64_C(256); + Value |= insn & UINT64_C(255); + MI.addOperand(MCOperand::createImm(Value << 3)); + // op: Rtt + Value = (insn >> 8) & UINT64_C(31); + DecodeDoubleRegsRegisterClass(MI, Value, 0, 0); + break; + } + + // op: g16_2 + case Hexagon::S2_storerinewabs: + ++shift; + // op: g16_1 + case Hexagon::S2_storerhnewabs: + ++shift; + // op: g16_0 + case Hexagon::S2_storerbnewabs: { + Value = (insn >> 11) & UINT64_C(49152); + Value |= (insn >> 7) & UINT64_C(15872); + Value |= (insn >> 5) & UINT64_C(256); + Value |= insn & UINT64_C(255); + MI.addOperand(MCOperand::createImm(Value << shift)); + // op: Nt + Value = (insn >> 8) & UINT64_C(7); + DecodeIntRegsRegisterClass(MI, Value, 0, 0); + break; + } + + // op: g16_2 + case Hexagon::S2_storeriabs: + ++shift; + // op: g16_1 + case Hexagon::S2_storerhabs: + case Hexagon::S2_storerfabs: + ++shift; + // op: g16_0 + case Hexagon::S2_storerbabs: { + Value = (insn >> 11) & UINT64_C(49152); + Value |= (insn >> 7) & UINT64_C(15872); + Value |= (insn >> 5) & UINT64_C(256); + Value |= insn & UINT64_C(255); + MI.addOperand(MCOperand::createImm(Value << shift)); + // op: Rt + Value = (insn >> 8) & UINT64_C(31); + DecodeIntRegsRegisterClass(MI, Value, 0, 0); + break; + } + } + return MCDisassembler::Success; + } + return MCDisassembler::Fail; +} + +static DecodeStatus decodeImmext(MCInst &MI, uint32_t insn, + void const *Decoder) { + + // Instruction Class for a constant a extender: bits 31:28 = 0x0000 + if ((~insn & 0xf0000000) == 0xf0000000) { + unsigned Value; + // 27:16 High 12 bits of 26-bit extender. + Value = (insn & 0x0fff0000) << 4; + // 13:0 Low 14 bits of 26-bit extender. + Value |= ((insn & 0x3fff) << 6); + MI.setOpcode(Hexagon::A4_ext); + HexagonMCInstrInfo::addConstant(MI, Value, contextFromDecoder(Decoder)); + return MCDisassembler::Success; + } + return MCDisassembler::Fail; +} + // These values are from HexagonGenMCCodeEmitter.inc and HexagonIsetDx.td enum subInstBinaryValues { V4_SA1_addi_BITS = 0x0000, @@ -807,6 +1350,8 @@ static unsigned getRegFromSubinstEncoding(unsigned encoded_reg) { return Hexagon::R0 + encoded_reg; else if (encoded_reg < 16) return Hexagon::R0 + encoded_reg + 8; + + // patently false value return Hexagon::NoRegister; } @@ -815,10 +1360,13 @@ static unsigned getDRegFromSubinstEncoding(unsigned encoded_dreg) { return Hexagon::D0 + encoded_dreg; else if (encoded_dreg < 8) return Hexagon::D0 + encoded_dreg + 4; + + // patently false value return Hexagon::NoRegister; } -static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { +void HexagonDisassembler::addSubinstOperands(MCInst *MI, unsigned opcode, + unsigned inst) const { int64_t operand; MCOperand Op; switch (opcode) { @@ -838,8 +1386,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { case Hexagon::V4_SS2_allocframe: // u 8-4{5_3} operand = ((inst & 0x1f0) >> 4) << 3; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SL1_loadri_io: // Rd 3-0, Rs 7-4, u 11-8{4_2} @@ -850,8 +1397,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = (inst & 0xf00) >> 6; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SL1_loadrub_io: // Rd 3-0, Rs 7-4, u 11-8 @@ -862,8 +1408,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = (inst & 0xf00) >> 8; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SL2_loadrb_io: // Rd 3-0, Rs 7-4, u 10-8 @@ -874,8 +1419,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = (inst & 0x700) >> 8; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SL2_loadrh_io: case Hexagon::V4_SL2_loadruh_io: @@ -887,8 +1431,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = ((inst & 0x700) >> 8) << 1; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SL2_loadrd_sp: // Rdd 2-0, u 7-3{5_3} @@ -896,8 +1439,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = ((inst & 0x0f8) >> 3) << 3; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SL2_loadri_sp: // Rd 3-0, u 8-4{5_2} @@ -905,8 +1447,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = ((inst & 0x1f0) >> 4) << 2; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SA1_addi: // Rx 3-0 (x2), s7 10-4 @@ -915,8 +1456,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { MI->addOperand(Op); MI->addOperand(Op); operand = SignExtend64<7>((inst & 0x7f0) >> 4); - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SA1_addrx: // Rx 3-0 (x2), Rs 7-4 @@ -949,8 +1489,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = ((inst & 0x3f0) >> 4) << 2; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SA1_seti: // Rd 3-0, u 9-4 @@ -958,8 +1497,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = (inst & 0x3f0) >> 4; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SA1_clrf: case Hexagon::V4_SA1_clrfnew: @@ -977,8 +1515,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = inst & 0x3; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SA1_combine0i: case Hexagon::V4_SA1_combine1i: @@ -989,8 +1526,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = (inst & 0x060) >> 5; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SA1_combinerz: case Hexagon::V4_SA1_combinezr: @@ -1008,8 +1544,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = (inst & 0xf00) >> 8; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); operand = getRegFromSubinstEncoding(inst & 0xf); Op = MCOperand::createReg(operand); MI->addOperand(Op); @@ -1020,8 +1555,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = ((inst & 0xf00) >> 8) << 2; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); operand = getRegFromSubinstEncoding(inst & 0xf); Op = MCOperand::createReg(operand); MI->addOperand(Op); @@ -1033,8 +1567,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = inst & 0xf; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SS2_storewi0: case Hexagon::V4_SS2_storewi1: @@ -1043,14 +1576,12 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = (inst & 0xf) << 2; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); break; case Hexagon::V4_SS2_stored_sp: // s 8-3{6_3}, Rtt 2-0 operand = SignExtend64<9>(((inst & 0x1f8) >> 3) << 3); - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); operand = getDRegFromSubinstEncoding(inst & 0x7); Op = MCOperand::createReg(operand); MI->addOperand(Op); @@ -1061,8 +1592,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { Op = MCOperand::createReg(operand); MI->addOperand(Op); operand = ((inst & 0x700) >> 8) << 1; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); operand = getRegFromSubinstEncoding(inst & 0xf); Op = MCOperand::createReg(operand); MI->addOperand(Op); @@ -1070,8 +1600,7 @@ static void AddSubinstOperands(MCInst *MI, unsigned opcode, unsigned inst) { case Hexagon::V4_SS2_storew_sp: // u 8-4{5_2}, Rd 3-0 operand = ((inst & 0x1f0) >> 4) << 2; - Op = MCOperand::createImm(operand); - MI->addOperand(Op); + HexagonMCInstrInfo::addConstant(*MI, operand, getContext()); operand = getRegFromSubinstEncoding(inst & 0xf); Op = MCOperand::createReg(operand); MI->addOperand(Op); diff --git a/lib/Target/Hexagon/Disassembler/LLVMBuild.txt b/lib/Target/Hexagon/Disassembler/LLVMBuild.txt index 43bace75a85..6c251020f81 100644 --- a/lib/Target/Hexagon/Disassembler/LLVMBuild.txt +++ b/lib/Target/Hexagon/Disassembler/LLVMBuild.txt @@ -19,5 +19,5 @@ type = Library name = HexagonDisassembler parent = Hexagon -required_libraries = HexagonDesc HexagonInfo MCDisassembler Support +required_libraries = HexagonDesc HexagonInfo MC MCDisassembler Support add_to_library_groups = Hexagon diff --git a/lib/Target/Hexagon/Hexagon.td b/lib/Target/Hexagon/Hexagon.td index c0631c4bbbd..ff70fb27b27 100644 --- a/lib/Target/Hexagon/Hexagon.td +++ b/lib/Target/Hexagon/Hexagon.td @@ -30,6 +30,9 @@ def ArchV60: SubtargetFeature<"v60", "HexagonArchVersion", "V60", "Hexagon V60"> // Hexagon ISA Extensions def ExtensionHVX: SubtargetFeature<"hvx", "UseHVXOps", "true", "Hexagon HVX instructions">; +def ExtensionHVXDbl: SubtargetFeature<"hvxDbl", "UseHVXDblOps", + "true", "Hexagon HVX Double instructions">; + //===----------------------------------------------------------------------===// // Hexagon Instruction Predicate Definitions. //===----------------------------------------------------------------------===// @@ -212,7 +215,13 @@ def : Proc<"hexagonv5", HexagonModelV4, // Declare the target which we are implementing //===----------------------------------------------------------------------===// +def HexagonAsmParserVariant : AsmParserVariant { + int Variant = 0; + string TokenizingCharacters = "#()=:.<>!+*"; +} + def Hexagon : Target { // Pull in Instruction Info: let InstructionSet = HexagonInstrInfo; + let AssemblyParserVariants = [HexagonAsmParserVariant]; } diff --git a/lib/Target/Hexagon/HexagonMCInstLower.cpp b/lib/Target/Hexagon/HexagonMCInstLower.cpp index 75189b696ea..82a9b23149c 100644 --- a/lib/Target/Hexagon/HexagonMCInstLower.cpp +++ b/lib/Target/Hexagon/HexagonMCInstLower.cpp @@ -73,11 +73,14 @@ void llvm::HexagonLowerToMC(MachineInstr const* MI, MCInst& MCB, APFloat Val = MO.getFPImm()->getValueAPF(); // FP immediates are used only when setting GPRs, so they may be dealt // with like regular immediates from this point on. - MCO = MCOperand::createImm(*Val.bitcastToAPInt().getRawData()); + MCO = MCOperand::createExpr( + MCConstantExpr::create(*Val.bitcastToAPInt().getRawData(), + AP.OutContext)); break; } case MachineOperand::MO_Immediate: - MCO = MCOperand::createImm(MO.getImm()); + MCO = MCOperand::createExpr( + MCConstantExpr::create(MO.getImm(), AP.OutContext)); break; case MachineOperand::MO_MachineBasicBlock: MCO = MCOperand::createExpr diff --git a/lib/Target/Hexagon/HexagonOperands.td b/lib/Target/Hexagon/HexagonOperands.td index 606511ec3bc..fbd29cd4d6d 100644 --- a/lib/Target/Hexagon/HexagonOperands.td +++ b/lib/Target/Hexagon/HexagonOperands.td @@ -1,4 +1,4 @@ -//===- HexagonOperands.td - Hexagon immediate processing -*- tablegen -*-===// +//===- HexagonImmediates.td - Hexagon immediate processing -*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -7,57 +7,100 @@ // //===----------------------------------------------------------------------===// +def s32ImmOperand : AsmOperandClass { let Name = "s32Imm"; } +def s8ImmOperand : AsmOperandClass { let Name = "s8Imm"; } +def s8Imm64Operand : AsmOperandClass { let Name = "s8Imm64"; } +def s6ImmOperand : AsmOperandClass { let Name = "s6Imm"; } +def s4ImmOperand : AsmOperandClass { let Name = "s4Imm"; } def s4_0ImmOperand : AsmOperandClass { let Name = "s4_0Imm"; } def s4_1ImmOperand : AsmOperandClass { let Name = "s4_1Imm"; } def s4_2ImmOperand : AsmOperandClass { let Name = "s4_2Imm"; } def s4_3ImmOperand : AsmOperandClass { let Name = "s4_3Imm"; } def s4_6ImmOperand : AsmOperandClass { let Name = "s4_6Imm"; } def s3_6ImmOperand : AsmOperandClass { let Name = "s3_6Imm"; } - +def u64ImmOperand : AsmOperandClass { let Name = "u64Imm"; } +def u32ImmOperand : AsmOperandClass { let Name = "u32Imm"; } +def u26_6ImmOperand : AsmOperandClass { let Name = "u26_6Imm"; } +def u16ImmOperand : AsmOperandClass { let Name = "u16Imm"; } +def u16_0ImmOperand : AsmOperandClass { let Name = "u16_0Imm"; } +def u16_1ImmOperand : AsmOperandClass { let Name = "u16_1Imm"; } +def u16_2ImmOperand : AsmOperandClass { let Name = "u16_2Imm"; } +def u16_3ImmOperand : AsmOperandClass { let Name = "u16_3Imm"; } +def u11_3ImmOperand : AsmOperandClass { let Name = "u11_3Imm"; } +def u10ImmOperand : AsmOperandClass { let Name = "u10Imm"; } +def u9ImmOperand : AsmOperandClass { let Name = "u9Imm"; } +def u8ImmOperand : AsmOperandClass { let Name = "u8Imm"; } +def u7ImmOperand : AsmOperandClass { let Name = "u7Imm"; } +def u6ImmOperand : AsmOperandClass { let Name = "u6Imm"; } +def u6_0ImmOperand : AsmOperandClass { let Name = "u6_0Imm"; } +def u6_1ImmOperand : AsmOperandClass { let Name = "u6_1Imm"; } +def u6_2ImmOperand : AsmOperandClass { let Name = "u6_2Imm"; } +def u6_3ImmOperand : AsmOperandClass { let Name = "u6_3Imm"; } +def u5ImmOperand : AsmOperandClass { let Name = "u5Imm"; } +def u4ImmOperand : AsmOperandClass { let Name = "u4Imm"; } +def u3ImmOperand : AsmOperandClass { let Name = "u3Imm"; } +def u2ImmOperand : AsmOperandClass { let Name = "u2Imm"; } +def u1ImmOperand : AsmOperandClass { let Name = "u1Imm"; } +def n8ImmOperand : AsmOperandClass { let Name = "n8Imm"; } // Immediate operands. -let PrintMethod = "printImmOperand" in { - def s32Imm : Operand; - def s8Imm : Operand; - def s8Imm64 : Operand; - def s6Imm : Operand; +let OperandType = "OPERAND_IMMEDIATE", + DecoderMethod = "unsignedImmDecoder" in { + def s32Imm : Operand { let ParserMatchClass = s32ImmOperand; + let DecoderMethod = "s32ImmDecoder"; } + def s8Imm : Operand { let ParserMatchClass = s8ImmOperand; + let DecoderMethod = "s8ImmDecoder"; } + def s8Imm64 : Operand { let ParserMatchClass = s8Imm64Operand; + let DecoderMethod = "s8ImmDecoder"; } + def s6Imm : Operand { let ParserMatchClass = s6ImmOperand; + let DecoderMethod = "s6_0ImmDecoder"; } def s6_3Imm : Operand; - def s4Imm : Operand; - def s4_0Imm : Operand { let DecoderMethod = "s4_0ImmDecoder"; } - def s4_1Imm : Operand { let DecoderMethod = "s4_1ImmDecoder"; } - def s4_2Imm : Operand { let DecoderMethod = "s4_2ImmDecoder"; } - def s4_3Imm : Operand { let DecoderMethod = "s4_3ImmDecoder"; } - def u64Imm : Operand; - def u32Imm : Operand; - def u26_6Imm : Operand; - def u16Imm : Operand; - def u16_0Imm : Operand; - def u16_1Imm : Operand; - def u16_2Imm : Operand; - def u16_3Imm : Operand; - def u11_3Imm : Operand; - def u10Imm : Operand; - def u9Imm : Operand; - def u8Imm : Operand; - def u7Imm : Operand; - def u6Imm : Operand; - def u6_0Imm : Operand; - def u6_1Imm : Operand; - def u6_2Imm : Operand; - def u6_3Imm : Operand; - def u5Imm : Operand; + def s4Imm : Operand { let ParserMatchClass = s4ImmOperand; + let DecoderMethod = "s4_0ImmDecoder"; } + def s4_0Imm : Operand { let ParserMatchClass = s4_0ImmOperand; + let DecoderMethod = "s4_0ImmDecoder"; } + def s4_1Imm : Operand { let ParserMatchClass = s4_1ImmOperand; + let DecoderMethod = "s4_1ImmDecoder"; } + def s4_2Imm : Operand { let ParserMatchClass = s4_2ImmOperand; + let DecoderMethod = "s4_2ImmDecoder"; } + def s4_3Imm : Operand { let ParserMatchClass = s4_3ImmOperand; + let DecoderMethod = "s4_3ImmDecoder"; } + def u64Imm : Operand { let ParserMatchClass = u64ImmOperand; } + def u32Imm : Operand { let ParserMatchClass = u32ImmOperand; } + def u26_6Imm : Operand { let ParserMatchClass = u26_6ImmOperand; } + def u16Imm : Operand { let ParserMatchClass = u16ImmOperand; } + def u16_0Imm : Operand { let ParserMatchClass = u16_0ImmOperand; } + def u16_1Imm : Operand { let ParserMatchClass = u16_1ImmOperand; } + def u16_2Imm : Operand { let ParserMatchClass = u16_2ImmOperand; } + def u16_3Imm : Operand { let ParserMatchClass = u16_3ImmOperand; } + def u11_3Imm : Operand { let ParserMatchClass = u11_3ImmOperand; } + def u10Imm : Operand { let ParserMatchClass = u10ImmOperand; } + def u9Imm : Operand { let ParserMatchClass = u9ImmOperand; } + def u8Imm : Operand { let ParserMatchClass = u8ImmOperand; } + def u7Imm : Operand { let ParserMatchClass = u7ImmOperand; } + def u6Imm : Operand { let ParserMatchClass = u6ImmOperand; } + def u6_0Imm : Operand { let ParserMatchClass = u6_0ImmOperand; } + def u6_1Imm : Operand { let ParserMatchClass = u6_1ImmOperand; } + def u6_2Imm : Operand { let ParserMatchClass = u6_2ImmOperand; } + def u6_3Imm : Operand { let ParserMatchClass = u6_3ImmOperand; } + def u5Imm : Operand { let ParserMatchClass = u5ImmOperand; } + def u5_0Imm : Operand; + def u5_1Imm : Operand; def u5_2Imm : Operand; def u5_3Imm : Operand; - def u4Imm : Operand; + def u4Imm : Operand { let ParserMatchClass = u4ImmOperand; } def u4_0Imm : Operand; + def u4_1Imm : Operand; def u4_2Imm : Operand; - def u3Imm : Operand; + def u4_3Imm : Operand; + def u3Imm : Operand { let ParserMatchClass = u3ImmOperand; } def u3_0Imm : Operand; def u3_1Imm : Operand; - def u2Imm : Operand; - def u1Imm : Operand; - def n8Imm : Operand; - def m6Imm : Operand; + def u3_2Imm : Operand; + def u3_3Imm : Operand; + def u2Imm : Operand { let ParserMatchClass = u2ImmOperand; } + def u1Imm : Operand { let ParserMatchClass = u1ImmOperand; } + def n8Imm : Operand { let ParserMatchClass = n8ImmOperand; } } let OperandType = "OPERAND_IMMEDIATE" in { @@ -73,9 +116,6 @@ let OperandType = "OPERAND_IMMEDIATE" in { let DecoderMethod = "s3_6ImmDecoder";} } -let PrintMethod = "printNOneImmOperand" in -def nOneImm : Operand; - // // Immediate predicates // @@ -169,7 +209,6 @@ def s4_3ImmPred : PatLeaf<(i32 imm), [{ return isShiftedInt<4,3>(v); }]>; - def u64ImmPred : PatLeaf<(i64 imm), [{ // Adding "N ||" to suppress gcc unused warning. return (N || true); @@ -225,6 +264,11 @@ def u11_3ImmPred : PatLeaf<(i32 imm), [{ return isShiftedUInt<11,3>(v); }]>; +def u10ImmPred : PatLeaf<(i32 imm), [{ + int64_t v = (int64_t)N->getSExtValue(); + return isUInt<10>(v); +}]>; + def u9ImmPred : PatLeaf<(i32 imm), [{ int64_t v = (int64_t)N->getSExtValue(); return isUInt<9>(v); @@ -296,6 +340,11 @@ def u1ImmPred : PatLeaf<(i1 imm), [{ return isUInt<1>(v); }]>; +def u1ImmPred32 : PatLeaf<(i32 imm), [{ + int64_t v = (int64_t)N->getSExtValue(); + return isUInt<1>(v); +}]>; + def m5BImmPred : PatLeaf<(i32 imm), [{ // m5BImmPred predicate - True if the (char) number is in range -1 .. -31 // and will fit in a 5 bit field when made positive, for use in memops. @@ -408,29 +457,65 @@ def SetClr3ImmPred : PatLeaf<(i32 imm), [{ // Extendable immediate operands. - -let PrintMethod = "printExtOperand" in { - def f32Ext : Operand; - def s16Ext : Operand { let DecoderMethod = "s16ImmDecoder"; } - def s12Ext : Operand { let DecoderMethod = "s12ImmDecoder"; } - def s11_0Ext : Operand { let DecoderMethod = "s11_0ImmDecoder"; } - def s11_1Ext : Operand { let DecoderMethod = "s11_1ImmDecoder"; } - def s11_2Ext : Operand { let DecoderMethod = "s11_2ImmDecoder"; } - def s11_3Ext : Operand { let DecoderMethod = "s11_3ImmDecoder"; } - def s10Ext : Operand { let DecoderMethod = "s10ImmDecoder"; } - def s9Ext : Operand { let DecoderMethod = "s90ImmDecoder"; } - def s8Ext : Operand { let DecoderMethod = "s8ImmDecoder"; } - def s7Ext : Operand; - def s6Ext : Operand { let DecoderMethod = "s6_0ImmDecoder"; } - def u6Ext : Operand; - def u7Ext : Operand; - def u8Ext : Operand; - def u9Ext : Operand; - def u10Ext : Operand; - def u6_0Ext : Operand; - def u6_1Ext : Operand; - def u6_2Ext : Operand; - def u6_3Ext : Operand; +def f32ExtOperand : AsmOperandClass { let Name = "f32Ext"; } +def s16ExtOperand : AsmOperandClass { let Name = "s16Ext"; } +def s12ExtOperand : AsmOperandClass { let Name = "s12Ext"; } +def s10ExtOperand : AsmOperandClass { let Name = "s10Ext"; } +def s9ExtOperand : AsmOperandClass { let Name = "s9Ext"; } +def s8ExtOperand : AsmOperandClass { let Name = "s8Ext"; } +def s7ExtOperand : AsmOperandClass { let Name = "s7Ext"; } +def s6ExtOperand : AsmOperandClass { let Name = "s6Ext"; } +def s11_0ExtOperand : AsmOperandClass { let Name = "s11_0Ext"; } +def s11_1ExtOperand : AsmOperandClass { let Name = "s11_1Ext"; } +def s11_2ExtOperand : AsmOperandClass { let Name = "s11_2Ext"; } +def s11_3ExtOperand : AsmOperandClass { let Name = "s11_3Ext"; } +def u6ExtOperand : AsmOperandClass { let Name = "u6Ext"; } +def u7ExtOperand : AsmOperandClass { let Name = "u7Ext"; } +def u8ExtOperand : AsmOperandClass { let Name = "u8Ext"; } +def u9ExtOperand : AsmOperandClass { let Name = "u9Ext"; } +def u10ExtOperand : AsmOperandClass { let Name = "u10Ext"; } +def u6_0ExtOperand : AsmOperandClass { let Name = "u6_0Ext"; } +def u6_1ExtOperand : AsmOperandClass { let Name = "u6_1Ext"; } +def u6_2ExtOperand : AsmOperandClass { let Name = "u6_2Ext"; } +def u6_3ExtOperand : AsmOperandClass { let Name = "u6_3Ext"; } +def u32MustExtOperand : AsmOperandClass { let Name = "u32MustExt"; } + + + +let OperandType = "OPERAND_IMMEDIATE", PrintMethod = "printExtOperand", + DecoderMethod = "unsignedImmDecoder" in { + def f32Ext : Operand { let ParserMatchClass = f32ExtOperand; } + def s16Ext : Operand { let ParserMatchClass = s16ExtOperand; + let DecoderMethod = "s16ImmDecoder"; } + def s12Ext : Operand { let ParserMatchClass = s12ExtOperand; + let DecoderMethod = "s12ImmDecoder"; } + def s11_0Ext : Operand { let ParserMatchClass = s11_0ExtOperand; + let DecoderMethod = "s11_0ImmDecoder"; } + def s11_1Ext : Operand { let ParserMatchClass = s11_1ExtOperand; + let DecoderMethod = "s11_1ImmDecoder"; } + def s11_2Ext : Operand { let ParserMatchClass = s11_2ExtOperand; + let DecoderMethod = "s11_2ImmDecoder"; } + def s11_3Ext : Operand { let ParserMatchClass = s11_3ExtOperand; + let DecoderMethod = "s11_3ImmDecoder"; } + def s10Ext : Operand { let ParserMatchClass = s10ExtOperand; + let DecoderMethod = "s10ImmDecoder"; } + def s9Ext : Operand { let ParserMatchClass = s9ExtOperand; + let DecoderMethod = "s90ImmDecoder"; } + def s8Ext : Operand { let ParserMatchClass = s8ExtOperand; + let DecoderMethod = "s8ImmDecoder"; } + def s7Ext : Operand { let ParserMatchClass = s7ExtOperand; } + def s6Ext : Operand { let ParserMatchClass = s6ExtOperand; + let DecoderMethod = "s6_0ImmDecoder"; } + def u6Ext : Operand { let ParserMatchClass = u6ExtOperand; } + def u7Ext : Operand { let ParserMatchClass = u7ExtOperand; } + def u8Ext : Operand { let ParserMatchClass = u8ExtOperand; } + def u9Ext : Operand { let ParserMatchClass = u9ExtOperand; } + def u10Ext : Operand { let ParserMatchClass = u10ExtOperand; } + def u6_0Ext : Operand { let ParserMatchClass = u6_0ExtOperand; } + def u6_1Ext : Operand { let ParserMatchClass = u6_1ExtOperand; } + def u6_2Ext : Operand { let ParserMatchClass = u6_2ExtOperand; } + def u6_3Ext : Operand { let ParserMatchClass = u6_3ExtOperand; } + def u32MustExt : Operand { let ParserMatchClass = u32MustExtOperand; } } @@ -492,21 +577,21 @@ let PrintMethod = "printGlobalOperand" in { let PrintMethod = "printJumpTable" in def jumptablebase : Operand; -def brtarget : Operand; +def brtarget : Operand { + let DecoderMethod = "brtargetDecoder"; + let PrintMethod = "printBrtarget"; +} def brtargetExt : Operand { - let PrintMethod = "printExtBrtarget"; + let DecoderMethod = "brtargetDecoder"; + let PrintMethod = "printBrtarget"; +} +def calltarget : Operand { + let DecoderMethod = "brtargetDecoder"; + let PrintMethod = "printBrtarget"; } -def calltarget : Operand; def bblabel : Operand; -def bbl : SDNode<"ISD::BasicBlock", SDTPtrLeaf , [], "BasicBlockSDNode">; - -def symbolHi32 : Operand { - let PrintMethod = "printSymbolHi"; -} -def symbolLo32 : Operand { - let PrintMethod = "printSymbolLo"; -} +def bbl : SDNode<"ISD::BasicBlock", SDTPtrLeaf, [], "BasicBlockSDNode">; // Return true if for a 32 to 64-bit sign-extended load. def is_sext_i32 : PatLeaf<(i64 DoubleRegs:$src1), [{ diff --git a/lib/Target/Hexagon/HexagonRegisterInfo.td b/lib/Target/Hexagon/HexagonRegisterInfo.td index 38073190506..2595f900b9b 100644 --- a/lib/Target/Hexagon/HexagonRegisterInfo.td +++ b/lib/Target/Hexagon/HexagonRegisterInfo.td @@ -137,20 +137,21 @@ let Namespace = "Hexagon" in { def LC1 : Rc<3, "lc1", ["c3"]>, DwarfRegNum<[70]>; def P3_0 : Rc<4, "p3:0", ["c4"], [P0, P1, P2, P3]>, DwarfRegNum<[71]>; - def C6 : Rc<6, "c6", [], [M0]>, DwarfRegNum<[72]>; - def C7 : Rc<7, "c7", [], [M1]>, DwarfRegNum<[73]>; + def C5 : Rc<5, "c5", ["c5"]>, DwarfRegNum<[72]>; // future use + def C6 : Rc<6, "c6", [], [M0]>, DwarfRegNum<[73]>; + def C7 : Rc<7, "c7", [], [M1]>, DwarfRegNum<[74]>; - def USR : Rc<8, "usr", ["c8"]>, DwarfRegNum<[74]> { + def USR : Rc<8, "usr", ["c8"]>, DwarfRegNum<[75]> { let SubRegIndices = [subreg_overflow]; let SubRegs = [USR_OVF]; } - def PC : Rc<9, "pc">, DwarfRegNum<[75]>; - def UGP : Rc<10, "ugp", ["c10"]>, DwarfRegNum<[76]>; - def GP : Rc<11, "gp">, DwarfRegNum<[77]>; - def CS0 : Rc<12, "cs0", ["c12"]>, DwarfRegNum<[78]>; - def CS1 : Rc<13, "cs1", ["c13"]>, DwarfRegNum<[79]>; - def UPCL : Rc<14, "upcyclelo", ["c14"]>, DwarfRegNum<[80]>; - def UPCH : Rc<15, "upcyclehi", ["c15"]>, DwarfRegNum<[81]>; + def PC : Rc<9, "pc">, DwarfRegNum<[76]>; + def UGP : Rc<10, "ugp", ["c10"]>, DwarfRegNum<[77]>; + def GP : Rc<11, "gp">, DwarfRegNum<[78]>; + def CS0 : Rc<12, "cs0", ["c12"]>, DwarfRegNum<[79]>; + def CS1 : Rc<13, "cs1", ["c13"]>, DwarfRegNum<[80]>; + def UPCL : Rc<14, "upcyclelo", ["c14"]>, DwarfRegNum<[81]>; + def UPCH : Rc<15, "upcyclehi", ["c15"]>, DwarfRegNum<[82]>; } // Control registers pairs. diff --git a/lib/Target/Hexagon/LLVMBuild.txt b/lib/Target/Hexagon/LLVMBuild.txt index 9d288af0214..5967d4a287e 100644 --- a/lib/Target/Hexagon/LLVMBuild.txt +++ b/lib/Target/Hexagon/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = Disassembler MCTargetDesc TargetInfo +subdirectories = AsmParser Disassembler MCTargetDesc TargetInfo [component_0] type = TargetGroup diff --git a/lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt b/lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt index 5403b106cbb..2c5d0dab284 100644 --- a/lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt +++ b/lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt @@ -3,10 +3,12 @@ add_llvm_library(LLVMHexagonDesc HexagonELFObjectWriter.cpp HexagonInstPrinter.cpp HexagonMCAsmInfo.cpp + HexagonMCChecker.cpp HexagonMCCodeEmitter.cpp HexagonMCCompound.cpp HexagonMCDuplexInfo.cpp HexagonMCELFStreamer.cpp + HexagonMCExpr.cpp HexagonMCInstrInfo.cpp HexagonMCShuffler.cpp HexagonMCTargetDesc.cpp diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h b/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h index f4d162ccf6a..a19bff98624 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h @@ -44,6 +44,25 @@ namespace HexagonII { TypeMEMOP = 9, TypeNV = 10, TypeDUPLEX = 11, + TypeCOMPOUND = 12, + TypeCVI_FIRST = 13, + TypeCVI_VA = TypeCVI_FIRST, + TypeCVI_VA_DV = 14, + TypeCVI_VX = 15, + TypeCVI_VX_DV = 16, + TypeCVI_VP = 17, + TypeCVI_VP_VS = 18, + TypeCVI_VS = 19, + TypeCVI_VINLANESAT= 20, + TypeCVI_VM_LD = 21, + TypeCVI_VM_TMP_LD = 22, + TypeCVI_VM_CUR_LD = 23, + TypeCVI_VM_VP_LDU = 24, + TypeCVI_VM_ST = 25, + TypeCVI_VM_NEW_ST = 26, + TypeCVI_VM_STU = 27, + TypeCVI_HIST = 28, + TypeCVI_LAST = TypeCVI_HIST, TypePREFIX = 30, // Such as extenders. TypeENDLOOP = 31 // Such as end of a HW loop. }; @@ -164,7 +183,15 @@ namespace HexagonII { // Floating-point instructions. FPPos = 48, - FPMask = 0x1 + FPMask = 0x1, + + // New-Value producer-2 instructions. + hasNewValuePos2 = 50, + hasNewValueMask2 = 0x1, + + // Which operand consumes or produces a new value. + NewValueOpPos2 = 51, + NewValueOpMask2 = 0x7 }; // *** The code above must match HexagonInstrFormat*.td *** // @@ -219,6 +246,26 @@ namespace HexagonII { INST_PARSE_EXTENDER = 0x00000000 }; + enum InstIClassBits { + INST_ICLASS_MASK = 0xf0000000, + INST_ICLASS_EXTENDER = 0x00000000, + INST_ICLASS_J_1 = 0x10000000, + INST_ICLASS_J_2 = 0x20000000, + INST_ICLASS_LD_ST_1 = 0x30000000, + INST_ICLASS_LD_ST_2 = 0x40000000, + INST_ICLASS_J_3 = 0x50000000, + INST_ICLASS_CR = 0x60000000, + INST_ICLASS_ALU32_1 = 0x70000000, + INST_ICLASS_XTYPE_1 = 0x80000000, + INST_ICLASS_LD = 0x90000000, + INST_ICLASS_ST = 0xa0000000, + INST_ICLASS_ALU32_2 = 0xb0000000, + INST_ICLASS_XTYPE_2 = 0xc0000000, + INST_ICLASS_XTYPE_3 = 0xd0000000, + INST_ICLASS_XTYPE_4 = 0xe0000000, + INST_ICLASS_ALU32_3 = 0xf0000000 + }; + } // End namespace HexagonII. } // End namespace llvm. diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp index 46a6ca4f783..06ccec53221 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.cpp @@ -12,13 +12,13 @@ //===----------------------------------------------------------------------===// #include "HexagonAsmPrinter.h" -#include "Hexagon.h" #include "HexagonInstPrinter.h" +#include "MCTargetDesc/HexagonBaseInfo.h" #include "MCTargetDesc/HexagonMCInstrInfo.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -28,63 +28,33 @@ using namespace llvm; #define GET_INSTRUCTION_NAME #include "HexagonGenAsmWriter.inc" -// Return the minimum value that a constant extendable operand can have -// without being extended. -static int getMinValue(uint64_t TSFlags) { - unsigned isSigned = - (TSFlags >> HexagonII::ExtentSignedPos) & HexagonII::ExtentSignedMask; - unsigned bits = - (TSFlags >> HexagonII::ExtentBitsPos) & HexagonII::ExtentBitsMask; - - if (isSigned) - return -1U << (bits - 1); - - return 0; -} - -// Return the maximum value that a constant extendable operand can have -// without being extended. -static int getMaxValue(uint64_t TSFlags) { - unsigned isSigned = - (TSFlags >> HexagonII::ExtentSignedPos) & HexagonII::ExtentSignedMask; - unsigned bits = - (TSFlags >> HexagonII::ExtentBitsPos) & HexagonII::ExtentBitsMask; - - if (isSigned) - return ~(-1U << (bits - 1)); - - return ~(-1U << bits); -} - -// Return true if the instruction must be extended. -static bool isExtended(uint64_t TSFlags) { - return (TSFlags >> HexagonII::ExtendedPos) & HexagonII::ExtendedMask; -} - -// Currently just used in an assert statement -static bool isExtendable(uint64_t TSFlags) LLVM_ATTRIBUTE_UNUSED; -// Return true if the instruction may be extended based on the operand value. -static bool isExtendable(uint64_t TSFlags) { - return (TSFlags >> HexagonII::ExtendablePos) & HexagonII::ExtendableMask; +HexagonInstPrinter::HexagonInstPrinter(MCAsmInfo const &MAI, + MCInstrInfo const &MII, + MCRegisterInfo const &MRI) + : MCInstPrinter(MAI, MII, MRI), MII(MII), HasExtender(false) { } StringRef HexagonInstPrinter::getOpcodeName(unsigned Opcode) const { return MII.getName(Opcode); } -void HexagonInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { - OS << getRegisterName(RegNo); +void HexagonInstPrinter::printRegName(raw_ostream &O, unsigned RegNo) const { + O << getRegName(RegNo); +} + +StringRef HexagonInstPrinter::getRegName(unsigned RegNo) const { + return getRegisterName(RegNo); } void HexagonInstPrinter::setExtender(MCInst const &MCI) { HasExtender = HexagonMCInstrInfo::isImmext(MCI); } -void HexagonInstPrinter::printInst(MCInst const *MI, raw_ostream &OS, - StringRef Annot, - MCSubtargetInfo const &STI) { +void HexagonInstPrinter::printInst(const MCInst *MI, raw_ostream &OS, + StringRef Annot, const MCSubtargetInfo &STI) { assert(HexagonMCInstrInfo::isBundle(*MI)); assert(HexagonMCInstrInfo::bundleSize(*MI) <= HEXAGON_PACKET_SIZE); + assert(HexagonMCInstrInfo::bundleSize(*MI) > 0); HasExtender = false; for (auto const &I : HexagonMCInstrInfo::bundleInstructions(*MI)) { MCInst const &MCI = *I.getInst(); @@ -116,173 +86,148 @@ void HexagonInstPrinter::printInst(MCInst const *MI, raw_ostream &OS, } } -void HexagonInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, +void HexagonInstPrinter::printOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { - const MCOperand& MO = MI->getOperand(OpNo); - + if (HexagonMCInstrInfo::getExtendableOp(MII, *MI) == OpNo && + (HasExtender || HexagonMCInstrInfo::isConstExtended(MII, *MI))) + O << "#"; + MCOperand const &MO = MI->getOperand(OpNo); if (MO.isReg()) { - printRegName(O, MO.getReg()); - } else if(MO.isExpr()) { - MO.getExpr()->print(O, &MAI); - } else if(MO.isImm()) { - printImmOperand(MI, OpNo, O); + O << getRegisterName(MO.getReg()); + } else if (MO.isExpr()) { + int64_t Value; + if (MO.getExpr()->evaluateAsAbsolute(Value)) + O << formatImm(Value); + else + O << *MO.getExpr(); } else { llvm_unreachable("Unknown operand"); } } -void HexagonInstPrinter::printImmOperand(const MCInst *MI, unsigned OpNo, +void HexagonInstPrinter::printExtOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { - const MCOperand& MO = MI->getOperand(OpNo); - - if(MO.isExpr()) { - MO.getExpr()->print(O, &MAI); - } else if(MO.isImm()) { - O << MI->getOperand(OpNo).getImm(); - } else { - llvm_unreachable("Unknown operand"); - } -} - -void HexagonInstPrinter::printExtOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O) const { - const MCOperand &MO = MI->getOperand(OpNo); - const MCInstrDesc &MII = getMII().get(MI->getOpcode()); - - assert((isExtendable(MII.TSFlags) || isExtended(MII.TSFlags)) && - "Expecting an extendable operand"); - - if (MO.isExpr() || isExtended(MII.TSFlags)) { - O << "#"; - } else if (MO.isImm()) { - int ImmValue = MO.getImm(); - if (ImmValue < getMinValue(MII.TSFlags) || - ImmValue > getMaxValue(MII.TSFlags)) - O << "#"; - } printOperand(MI, OpNo, O); } -void HexagonInstPrinter::printUnsignedImmOperand(const MCInst *MI, - unsigned OpNo, raw_ostream &O) const { +void HexagonInstPrinter::printUnsignedImmOperand(MCInst const *MI, + unsigned OpNo, + raw_ostream &O) const { O << MI->getOperand(OpNo).getImm(); } -void HexagonInstPrinter::printNegImmOperand(const MCInst *MI, unsigned OpNo, +void HexagonInstPrinter::printNegImmOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { O << -MI->getOperand(OpNo).getImm(); } -void HexagonInstPrinter::printNOneImmOperand(const MCInst *MI, unsigned OpNo, +void HexagonInstPrinter::printNOneImmOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { O << -1; } void HexagonInstPrinter::prints3_6ImmOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { - int64_t Imm = MI->getOperand(OpNo).getImm(); + int64_t Imm; + bool Success = MI->getOperand(OpNo).getExpr()->evaluateAsAbsolute(Imm); + Imm = SignExtend64<9>(Imm); + assert(Success); (void)Success; assert(((Imm & 0x3f) == 0) && "Lower 6 bits must be ZERO."); O << formatImm(Imm/64); } void HexagonInstPrinter::prints3_7ImmOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { - int64_t Imm = MI->getOperand(OpNo).getImm(); + int64_t Imm; + bool Success = MI->getOperand(OpNo).getExpr()->evaluateAsAbsolute(Imm); + Imm = SignExtend64<10>(Imm); + assert(Success); (void)Success; assert(((Imm & 0x7f) == 0) && "Lower 7 bits must be ZERO."); O << formatImm(Imm/128); } void HexagonInstPrinter::prints4_6ImmOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { - int64_t Imm = MI->getOperand(OpNo).getImm(); + int64_t Imm; + bool Success = MI->getOperand(OpNo).getExpr()->evaluateAsAbsolute(Imm); + Imm = SignExtend64<10>(Imm); + assert(Success); (void)Success; assert(((Imm & 0x3f) == 0) && "Lower 6 bits must be ZERO."); O << formatImm(Imm/64); } void HexagonInstPrinter::prints4_7ImmOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { - int64_t Imm = MI->getOperand(OpNo).getImm(); + int64_t Imm; + bool Success = MI->getOperand(OpNo).getExpr()->evaluateAsAbsolute(Imm); + Imm = SignExtend64<11>(Imm); + assert(Success); (void)Success; assert(((Imm & 0x7f) == 0) && "Lower 7 bits must be ZERO."); O << formatImm(Imm/128); } -void HexagonInstPrinter::printMEMriOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O) const { - const MCOperand& MO0 = MI->getOperand(OpNo); - const MCOperand& MO1 = MI->getOperand(OpNo + 1); - - printRegName(O, MO0.getReg()); - O << " + #" << MO1.getImm(); -} - -void HexagonInstPrinter::printFrameIndexOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O) const { - const MCOperand& MO0 = MI->getOperand(OpNo); - const MCOperand& MO1 = MI->getOperand(OpNo + 1); - - printRegName(O, MO0.getReg()); - O << ", #" << MO1.getImm(); -} - -void HexagonInstPrinter::printGlobalOperand(const MCInst *MI, unsigned OpNo, +void HexagonInstPrinter::printGlobalOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { - assert(MI->getOperand(OpNo).isExpr() && "Expecting expression"); - printOperand(MI, OpNo, O); } -void HexagonInstPrinter::printJumpTable(const MCInst *MI, unsigned OpNo, +void HexagonInstPrinter::printJumpTable(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { assert(MI->getOperand(OpNo).isExpr() && "Expecting expression"); printOperand(MI, OpNo, O); } -void HexagonInstPrinter::printConstantPool(const MCInst *MI, unsigned OpNo, +void HexagonInstPrinter::printConstantPool(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { assert(MI->getOperand(OpNo).isExpr() && "Expecting expression"); printOperand(MI, OpNo, O); } -void HexagonInstPrinter::printBranchOperand(const MCInst *MI, unsigned OpNo, +void HexagonInstPrinter::printBranchOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { // Branches can take an immediate operand. This is used by the branch // selection pass to print $+8, an eight byte displacement from the PC. llvm_unreachable("Unknown branch operand."); } -void HexagonInstPrinter::printCallOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O) const { -} +void HexagonInstPrinter::printCallOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const {} -void HexagonInstPrinter::printAbsAddrOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O) const { -} +void HexagonInstPrinter::printAbsAddrOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const {} -void HexagonInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O) const { -} +void HexagonInstPrinter::printPredicateOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const {} -void HexagonInstPrinter::printSymbol(const MCInst *MI, unsigned OpNo, +void HexagonInstPrinter::printSymbol(MCInst const *MI, unsigned OpNo, raw_ostream &O, bool hi) const { - assert(MI->getOperand(OpNo).isImm() && "Unknown symbol operand"); + MCOperand const &MO = MI->getOperand(OpNo); - O << '#' << (hi ? "HI" : "LO") << "(#"; - printOperand(MI, OpNo, O); + O << '#' << (hi ? "HI" : "LO") << '('; + if (MO.isImm()) { + O << '#'; + printOperand(MI, OpNo, O); + } else { + printOperand(MI, OpNo, O); + assert("Unknown symbol operand"); + } O << ')'; } -void HexagonInstPrinter::printExtBrtarget(const MCInst *MI, unsigned OpNo, - raw_ostream &O) const { - const MCOperand &MO = MI->getOperand(OpNo); - const MCInstrDesc &MII = getMII().get(MI->getOpcode()); - - assert((isExtendable(MII.TSFlags) || isExtended(MII.TSFlags)) && - "Expecting an extendable operand"); - - if (MO.isExpr() || isExtended(MII.TSFlags)) { - O << "##"; +void HexagonInstPrinter::printBrtarget(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const { + MCOperand const &MO = MI->getOperand(OpNo); + assert (MO.isExpr()); + MCExpr const &Expr = *MO.getExpr(); + int64_t Value; + if (Expr.evaluateAsAbsolute(Value)) + O << format("0x%" PRIx64, Value); + else { + if (HasExtender || HexagonMCInstrInfo::isConstExtended(MII, *MI)) + if (HexagonMCInstrInfo::getExtendableOp(MII, *MI) == OpNo) + O << "##"; + O << Expr; } - printOperand(MI, OpNo, O); } diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.h b/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.h index 68a71fc310b..5f421184b20 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.h +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonInstPrinter.h @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// // -// This class prints an Hexagon MCInst to a .s file. // //===----------------------------------------------------------------------===// @@ -15,7 +14,6 @@ #define LLVM_LIB_TARGET_HEXAGON_INSTPRINTER_HEXAGONINSTPRINTER_H #include "llvm/MC/MCInstPrinter.h" -#include "llvm/MC/MCInstrInfo.h" namespace llvm { /// Prints bundles as a newline separated list of individual instructions @@ -25,76 +23,69 @@ namespace llvm { /// r0 = add(r1, r2) /// r0 = #0 \v jump 0x0 /// :endloop0 :endloop1 - class HexagonInstPrinter : public MCInstPrinter { - public: - explicit HexagonInstPrinter(MCAsmInfo const &MAI, - MCInstrInfo const &MII, - MCRegisterInfo const &MRI) - : MCInstPrinter(MAI, MII, MRI), MII(MII) {} +class HexagonInstPrinter : public MCInstPrinter { +public: + explicit HexagonInstPrinter(MCAsmInfo const &MAI, MCInstrInfo const &MII, + MCRegisterInfo const &MRI); + void printInst(MCInst const *MI, raw_ostream &O, StringRef Annot, + const MCSubtargetInfo &STI) override; + virtual StringRef getOpcodeName(unsigned Opcode) const; + void printInstruction(MCInst const *MI, raw_ostream &O); - void printInst(MCInst const *MI, raw_ostream &O, StringRef Annot, - const MCSubtargetInfo &STI) override; - virtual StringRef getOpcodeName(unsigned Opcode) const; - void printInstruction(const MCInst *MI, raw_ostream &O); - void printRegName(raw_ostream &OS, unsigned RegNo) const override; - static const char *getRegisterName(unsigned RegNo); + StringRef getRegName(unsigned RegNo) const; + static char const *getRegisterName(unsigned RegNo); + void printRegName(raw_ostream &O, unsigned RegNo) const override; - void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) const; - void printImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) const; - void printExtOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) const; - void printUnsignedImmOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O) const; - void printNegImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) - const; - void printNOneImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) - const; - void prints3_6ImmOperand(MCInst const *MI, unsigned OpNo, - raw_ostream &O) const; - void prints3_7ImmOperand(MCInst const *MI, unsigned OpNo, - raw_ostream &O) const; - void prints4_6ImmOperand(MCInst const *MI, unsigned OpNo, - raw_ostream &O) const; - void prints4_7ImmOperand(MCInst const *MI, unsigned OpNo, + void printOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const; + void printExtOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const; + void printUnsignedImmOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const; + void printNegImmOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const; + void printNOneImmOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const; + void prints3_6ImmOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const; + void prints3_7ImmOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const; + void prints4_6ImmOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const; + void prints4_7ImmOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const; + void printBranchOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const; + void printCallOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const; + void printAbsAddrOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const; + void printPredicateOperand(MCInst const *MI, unsigned OpNo, raw_ostream &O) const; - void printMEMriOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) - const; - void printFrameIndexOperand(const MCInst *MI, unsigned OpNo, - raw_ostream &O) const; - void printBranchOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) - const; - void printCallOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) - const; - void printAbsAddrOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) - const; - void printPredicateOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) - const; - void printGlobalOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) - const; - void printJumpTable(const MCInst *MI, unsigned OpNo, raw_ostream &O) const; - void printExtBrtarget(const MCInst *MI, unsigned OpNo, raw_ostream &O) const; + void printGlobalOperand(MCInst const *MI, unsigned OpNo, + raw_ostream &O) const; + void printJumpTable(MCInst const *MI, unsigned OpNo, raw_ostream &O) const; + void printBrtarget(MCInst const *MI, unsigned OpNo, raw_ostream &O) const; - void printConstantPool(const MCInst *MI, unsigned OpNo, - raw_ostream &O) const; + void printConstantPool(MCInst const *MI, unsigned OpNo, raw_ostream &O) const; - void printSymbolHi(const MCInst *MI, unsigned OpNo, raw_ostream &O) const - { printSymbol(MI, OpNo, O, true); } - void printSymbolLo(const MCInst *MI, unsigned OpNo, raw_ostream &O) const - { printSymbol(MI, OpNo, O, false); } + void printSymbolHi(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { + printSymbol(MI, OpNo, O, true); + } + void printSymbolLo(MCInst const *MI, unsigned OpNo, raw_ostream &O) const { + printSymbol(MI, OpNo, O, false); + } - const MCInstrInfo &getMII() const { - return MII; - } + MCAsmInfo const &getMAI() const { return MAI; } + MCInstrInfo const &getMII() const { return MII; } - protected: - void printSymbol(const MCInst *MI, unsigned OpNo, raw_ostream &O, bool hi) - const; +protected: + void printSymbol(MCInst const *MI, unsigned OpNo, raw_ostream &O, + bool hi) const; - private: - const MCInstrInfo &MII; +private: + MCInstrInfo const &MII; - bool HasExtender; - void setExtender(MCInst const &MCI); - }; + bool HasExtender; + void setExtender(MCInst const &MCI); +}; } // end namespace llvm diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp new file mode 100644 index 00000000000..c11abc1f42f --- /dev/null +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.cpp @@ -0,0 +1,580 @@ +//===----- HexagonMCChecker.cpp - Instruction bundle checking -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements the checking of insns inside a bundle according to the +// packet constraint rules of the Hexagon ISA. +// +//===----------------------------------------------------------------------===// + +#include "HexagonMCChecker.h" + +#include "HexagonBaseInfo.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static cl::opt RelaxNVChecks("relax-nv-checks", cl::init(false), + cl::ZeroOrMore, cl::Hidden, cl::desc("Relax checks of new-value validity")); + +const HexagonMCChecker::PredSense + HexagonMCChecker::Unconditional(Hexagon::NoRegister, false); + +void HexagonMCChecker::init() { + // Initialize read-only registers set. + ReadOnly.insert(Hexagon::PC); + + // Figure out the loop-registers definitions. + if (HexagonMCInstrInfo::isInnerLoop(MCB)) { + Defs[Hexagon::SA0].insert(Unconditional); // FIXME: define or change SA0? + Defs[Hexagon::LC0].insert(Unconditional); + } + if (HexagonMCInstrInfo::isOuterLoop(MCB)) { + Defs[Hexagon::SA1].insert(Unconditional); // FIXME: define or change SA0? + Defs[Hexagon::LC1].insert(Unconditional); + } + + if (HexagonMCInstrInfo::isBundle(MCB)) + // Unfurl a bundle. + for (auto const&I : HexagonMCInstrInfo::bundleInstructions(MCB)) { + init(*I.getInst()); + } + else + init(MCB); +} + +void HexagonMCChecker::init(MCInst const& MCI) { + const MCInstrDesc& MCID = HexagonMCInstrInfo::getDesc(MCII, MCI); + unsigned PredReg = Hexagon::NoRegister; + bool isTrue = false; + + // Get used registers. + for (unsigned i = MCID.getNumDefs(); i < MCID.getNumOperands(); ++i) + if (MCI.getOperand(i).isReg()) { + unsigned R = MCI.getOperand(i).getReg(); + + if (HexagonMCInstrInfo::isPredicated(MCII, MCI) && isPredicateRegister(R)) { + // Note an used predicate register. + PredReg = R; + isTrue = HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI); + + // Note use of new predicate register. + if (HexagonMCInstrInfo::isPredicatedNew(MCII, MCI)) + NewPreds.insert(PredReg); + } + else + // Note register use. Super-registers are not tracked directly, + // but their components. + for(MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid()); + SRI.isValid(); + ++SRI) + if (!MCSubRegIterator(*SRI, &RI).isValid()) + // Skip super-registers used indirectly. + Uses.insert(*SRI); + } + + // Get implicit register definitions. + const uint16_t* ImpDefs = MCID.getImplicitDefs(); + for (unsigned i = 0; i < MCID.getNumImplicitDefs(); ++i) { + unsigned R = ImpDefs[i]; + + if (Hexagon::R31 != R && MCID.isCall()) + // Any register other than the LR and the PC are actually volatile ones + // as defined by the ABI, not modified implicitly by the call insn. + continue; + if (Hexagon::PC == R) + // Branches are the only insns that can change the PC, + // otherwise a read-only register. + continue; + + if (Hexagon::USR_OVF == R) + // Many insns change the USR implicitly, but only one or another flag. + // The instruction table models the USR.OVF flag, which can be implicitly + // modified more than once, but cannot be modified in the same packet + // with an instruction that modifies is explicitly. Deal with such situ- + // ations individually. + SoftDefs.insert(R); + else if (isPredicateRegister(R) && HexagonMCInstrInfo::isPredicateLate(MCII, MCI)) + // Include implicit late predicates. + LatePreds.insert(R); + else + Defs[R].insert(PredSense(PredReg, isTrue)); + } + + // Figure out explicit register definitions. + for (unsigned i = 0; i < MCID.getNumDefs(); ++i) { + unsigned R = MCI.getOperand(i).getReg(), + S = Hexagon::NoRegister; + + // Note register definitions, direct ones as well as indirect side-effects. + // Super-registers are not tracked directly, but their components. + for(MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid()); + SRI.isValid(); + ++SRI) { + if (MCSubRegIterator(*SRI, &RI).isValid()) + // Skip super-registers defined indirectly. + continue; + + if (R == *SRI) { + if (S == R) + // Avoid scoring the defined register multiple times. + continue; + else + // Note that the defined register has already been scored. + S = R; + } + + if (Hexagon::P3_0 != R && Hexagon::P3_0 == *SRI) + // P3:0 is a special case, since multiple predicate register definitions + // in a packet is allowed as the equivalent of their logical "and". + // Only an explicit definition of P3:0 is noted as such; if a + // side-effect, then note as a soft definition. + SoftDefs.insert(*SRI); + else if (HexagonMCInstrInfo::isPredicateLate(MCII, MCI) && isPredicateRegister(*SRI)) + // Some insns produce predicates too late to be used in the same packet. + LatePreds.insert(*SRI); + else if (i == 0 && llvm::HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCVI_VM_CUR_LD) + // Current loads should be used in the same packet. + // TODO: relies on the impossibility of a current and a temporary loads + // in the same packet. + CurDefs.insert(*SRI), Defs[*SRI].insert(PredSense(PredReg, isTrue)); + else if (i == 0 && llvm::HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCVI_VM_TMP_LD) + // Temporary loads should be used in the same packet, but don't commit + // results, so it should be disregarded if another insn changes the same + // register. + // TODO: relies on the impossibility of a current and a temporary loads + // in the same packet. + TmpDefs.insert(*SRI); + else if (i <= 1 && llvm::HexagonMCInstrInfo::hasNewValue2(MCII, MCI) ) + // vshuff(Vx, Vy, Rx) <- Vx(0) and Vy(1) are both source and + // destination registers with this instruction. same for vdeal(Vx,Vy,Rx) + Uses.insert(*SRI); + else + Defs[*SRI].insert(PredSense(PredReg, isTrue)); + } + } + + // Figure out register definitions that produce new values. + if (HexagonMCInstrInfo::hasNewValue(MCII, MCI)) { + unsigned R = HexagonMCInstrInfo::getNewValueOperand(MCII, MCI).getReg(); + + if (HexagonMCInstrInfo::isCompound(MCII, MCI)) + compoundRegisterMap(R); // Compound insns have a limited register range. + + for(MCRegAliasIterator SRI(R, &RI, !MCSubRegIterator(R, &RI).isValid()); + SRI.isValid(); + ++SRI) + if (!MCSubRegIterator(*SRI, &RI).isValid()) + // No super-registers defined indirectly. + NewDefs[*SRI].push_back(NewSense::Def(PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI), + HexagonMCInstrInfo::isFloat(MCII, MCI))); + + // For fairly unique 2-dot-new producers, example: + // vdeal(V1, V9, R0) V1.new and V9.new can be used by consumers. + if (HexagonMCInstrInfo::hasNewValue2(MCII, MCI)) { + unsigned R2 = HexagonMCInstrInfo::getNewValueOperand2(MCII, MCI).getReg(); + + for(MCRegAliasIterator SRI(R2, &RI, !MCSubRegIterator(R2, &RI).isValid()); + SRI.isValid(); + ++SRI) + if (!MCSubRegIterator(*SRI, &RI).isValid()) + NewDefs[*SRI].push_back(NewSense::Def(PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI), + HexagonMCInstrInfo::isFloat(MCII, MCI))); + } + } + + // Figure out definitions of new predicate registers. + if (HexagonMCInstrInfo::isPredicatedNew(MCII, MCI)) + for (unsigned i = MCID.getNumDefs(); i < MCID.getNumOperands(); ++i) + if (MCI.getOperand(i).isReg()) { + unsigned P = MCI.getOperand(i).getReg(); + + if (isPredicateRegister(P)) + NewPreds.insert(P); + } + + // Figure out uses of new values. + if (HexagonMCInstrInfo::isNewValue(MCII, MCI)) { + unsigned N = HexagonMCInstrInfo::getNewValueOperand(MCII, MCI).getReg(); + + if (!MCSubRegIterator(N, &RI).isValid()) { + // Super-registers cannot use new values. + if (MCID.isBranch()) + NewUses[N] = NewSense::Jmp(llvm::HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeNV); + else + NewUses[N] = NewSense::Use(PredReg, HexagonMCInstrInfo::isPredicatedTrue(MCII, MCI)); + } + } +} + +HexagonMCChecker::HexagonMCChecker(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst &mcb, MCInst &mcbdx, + MCRegisterInfo const &ri) + : MCB(mcb), MCBDX(mcbdx), RI(ri), MCII(MCII), STI(STI), + bLoadErrInfo(false) { + init(); +} + +bool HexagonMCChecker::check() { + bool chkB = checkBranches(); + bool chkP = checkPredicates(); + bool chkNV = checkNewValues(); + bool chkR = checkRegisters(); + bool chkS = checkSolo(); + bool chkSh = checkShuffle(); + bool chkSl = checkSlots(); + bool chk = chkB && chkP && chkNV && chkR && chkS && chkSh && chkSl; + + return chk; +} + +bool HexagonMCChecker::checkSlots() + +{ + unsigned slotsUsed = 0; + for (auto HMI: HexagonMCInstrInfo::bundleInstructions(MCBDX)) { + MCInst const& MCI = *HMI.getInst(); + if (HexagonMCInstrInfo::isImmext(MCI)) + continue; + if (HexagonMCInstrInfo::isDuplex(MCII, MCI)) + slotsUsed += 2; + else + ++slotsUsed; + } + + if (slotsUsed > HEXAGON_PACKET_SIZE) { + HexagonMCErrInfo errInfo; + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_NOSLOTS); + addErrInfo(errInfo); + return false; + } + return true; +} + +// Check legal use of branches. +bool HexagonMCChecker::checkBranches() { + HexagonMCErrInfo errInfo; + if (HexagonMCInstrInfo::isBundle(MCB)) { + bool hasConditional = false; + unsigned Branches = 0, Returns = 0, NewIndirectBranches = 0, + NewValueBranches = 0, Conditional = HEXAGON_PRESHUFFLE_PACKET_SIZE, + Unconditional = HEXAGON_PRESHUFFLE_PACKET_SIZE; + + for (unsigned i = HexagonMCInstrInfo::bundleInstructionsOffset; + i < MCB.size(); ++i) { + MCInst const &MCI = *MCB.begin()[i].getInst(); + + if (HexagonMCInstrInfo::isImmext(MCI)) + continue; + if (HexagonMCInstrInfo::getDesc(MCII, MCI).isBranch() || + HexagonMCInstrInfo::getDesc(MCII, MCI).isCall()) { + ++Branches; + if (HexagonMCInstrInfo::getDesc(MCII, MCI).isIndirectBranch() && + HexagonMCInstrInfo::isPredicatedNew(MCII, MCI)) + ++NewIndirectBranches; + if (HexagonMCInstrInfo::isNewValue(MCII, MCI)) + ++NewValueBranches; + + if (HexagonMCInstrInfo::isPredicated(MCII, MCI) || + HexagonMCInstrInfo::isPredicatedNew(MCII, MCI)) { + hasConditional = true; + Conditional = i; // Record the position of the conditional branch. + } else { + Unconditional = i; // Record the position of the unconditional branch. + } + } + if (HexagonMCInstrInfo::getDesc(MCII, MCI).isReturn() && + HexagonMCInstrInfo::getDesc(MCII, MCI).mayLoad()) + ++Returns; + } + + if (Branches) // FIXME: should "Defs.count(Hexagon::PC)" be here too? + if (HexagonMCInstrInfo::isInnerLoop(MCB) || + HexagonMCInstrInfo::isOuterLoop(MCB)) { + // Error out if there's any branch in a loop-end packet. + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_ENDLOOP, Hexagon::PC); + addErrInfo(errInfo); + return false; + } + if (Branches > 1) + if (!hasConditional || Conditional > Unconditional) { + // Error out if more than one unconditional branch or + // the conditional branch appears after the unconditional one. + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_BRANCHES); + addErrInfo(errInfo); + return false; + } + } + + return true; +} + +// Check legal use of predicate registers. +bool HexagonMCChecker::checkPredicates() { + HexagonMCErrInfo errInfo; + // Check for proper use of new predicate registers. + for (const auto& I : NewPreds) { + unsigned P = I; + + if (!Defs.count(P) || LatePreds.count(P)) { + // Error out if the new predicate register is not defined, + // or defined "late" + // (e.g., "{ if (p3.new)... ; p3 = sp1loop0(#r7:2, Rs) }"). + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_NEWP, P); + addErrInfo(errInfo); + return false; + } + } + + // Check for proper use of auto-anded of predicate registers. + for (const auto& I : LatePreds) { + unsigned P = I; + + if (LatePreds.count(P) > 1 || Defs.count(P)) { + // Error out if predicate register defined "late" multiple times or + // defined late and regularly defined + // (e.g., "{ p3 = sp1loop0(...); p3 = cmp.eq(...) }". + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, P); + addErrInfo(errInfo); + return false; + } + } + + return true; +} + +// Check legal use of new values. +bool HexagonMCChecker::checkNewValues() { + HexagonMCErrInfo errInfo; + memset(&errInfo, 0, sizeof(errInfo)); + for (auto& I : NewUses) { + unsigned R = I.first; + NewSense &US = I.second; + + if (!hasValidNewValueDef(US, NewDefs[R])) { + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_NEWV, R); + addErrInfo(errInfo); + return false; + } + } + + return true; +} + +// Check for legal register uses and definitions. +bool HexagonMCChecker::checkRegisters() { + HexagonMCErrInfo errInfo; + // Check for proper register definitions. + for (const auto& I : Defs) { + unsigned R = I.first; + + if (ReadOnly.count(R)) { + // Error out for definitions of read-only registers. + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_READONLY, R); + addErrInfo(errInfo); + return false; + } + if (isLoopRegister(R) && Defs.count(R) > 1 && + (HexagonMCInstrInfo::isInnerLoop(MCB) || + HexagonMCInstrInfo::isOuterLoop(MCB))) { + // Error out for definitions of loop registers at the end of a loop. + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_LOOP, R); + addErrInfo(errInfo); + return false; + } + if (SoftDefs.count(R)) { + // Error out for explicit changes to registers also weakly defined + // (e.g., "{ usr = r0; r0 = sfadd(...) }"). + unsigned UsrR = Hexagon::USR; // Silence warning about mixed types in ?:. + unsigned BadR = RI.isSubRegister(Hexagon::USR, R) ? UsrR : R; + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, BadR); + addErrInfo(errInfo); + return false; + } + if (!isPredicateRegister(R) && Defs[R].size() > 1) { + // Check for multiple register definitions. + PredSet &PM = Defs[R]; + + // Check for multiple unconditional register definitions. + if (PM.count(Unconditional)) { + // Error out on an unconditional change when there are any other + // changes, conditional or not. + unsigned UsrR = Hexagon::USR; + unsigned BadR = RI.isSubRegister(Hexagon::USR, R) ? UsrR : R; + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, BadR); + addErrInfo(errInfo); + return false; + } + // Check for multiple conditional register definitions. + for (const auto& J : PM) { + PredSense P = J; + + // Check for multiple uses of the same condition. + if (PM.count(P) > 1) { + // Error out on conditional changes based on the same predicate + // (e.g., "{ if (!p0) r0 =...; if (!p0) r0 =... }"). + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, R); + addErrInfo(errInfo); + return false; + } + // Check for the use of the complementary condition. + P.second = !P.second; + if (PM.count(P) && PM.size() > 2) { + // Error out on conditional changes based on the same predicate + // multiple times + // (e.g., "{ if (p0) r0 =...; if (!p0) r0 =... }; if (!p0) r0 =... }"). + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_REGISTERS, R); + addErrInfo(errInfo); + return false; + } + } + } + } + + // Check for use of current definitions. + for (const auto& I : CurDefs) { + unsigned R = I; + + if (!Uses.count(R)) { + // Warn on an unused current definition. + errInfo.setWarning(HexagonMCErrInfo::CHECK_WARN_CURRENT, R); + addErrInfo(errInfo); + return true; + } + } + + // Check for use of temporary definitions. + for (const auto& I : TmpDefs) { + unsigned R = I; + + if (!Uses.count(R)) { + // special case for vhist + bool vHistFound = false; + for (auto const&HMI : HexagonMCInstrInfo::bundleInstructions(MCB)) { + if(llvm::HexagonMCInstrInfo::getType(MCII, *HMI.getInst()) == HexagonII::TypeCVI_HIST) { + vHistFound = true; // vhist() implicitly uses ALL REGxx.tmp + break; + } + } + // Warn on an unused temporary definition. + if (vHistFound == false) { + errInfo.setWarning(HexagonMCErrInfo::CHECK_WARN_TEMPORARY, R); + addErrInfo(errInfo); + return true; + } + } + } + + return true; +} + +// Check for legal use of solo insns. +bool HexagonMCChecker::checkSolo() { + HexagonMCErrInfo errInfo; + if (HexagonMCInstrInfo::isBundle(MCB) && + HexagonMCInstrInfo::bundleSize(MCB) > 1) { + for (auto const&I : HexagonMCInstrInfo::bundleInstructions(MCB)) { + if (llvm::HexagonMCInstrInfo::isSolo(MCII, *I.getInst())) { + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_SOLO); + addErrInfo(errInfo); + return false; + } + } + } + + return true; +} + +bool HexagonMCChecker::checkShuffle() { + HexagonMCErrInfo errInfo; + // Branch info is lost when duplexing. The unduplexed insns must be + // checked and only branch errors matter for this case. + HexagonMCShuffler MCS(MCII, STI, MCB); + if (!MCS.check()) { + if (MCS.getError() == HexagonShuffler::SHUFFLE_ERROR_BRANCHES) { + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_SHUFFLE); + errInfo.setShuffleError(MCS.getError()); + addErrInfo(errInfo); + return false; + } + } + HexagonMCShuffler MCSDX(MCII, STI, MCBDX); + if (!MCSDX.check()) { + errInfo.setError(HexagonMCErrInfo::CHECK_ERROR_SHUFFLE); + errInfo.setShuffleError(MCSDX.getError()); + addErrInfo(errInfo); + return false; + } + return true; +} + +void HexagonMCChecker::compoundRegisterMap(unsigned& Register) { + switch (Register) { + default: + break; + case Hexagon::R15: + Register = Hexagon::R23; + break; + case Hexagon::R14: + Register = Hexagon::R22; + break; + case Hexagon::R13: + Register = Hexagon::R21; + break; + case Hexagon::R12: + Register = Hexagon::R20; + break; + case Hexagon::R11: + Register = Hexagon::R19; + break; + case Hexagon::R10: + Register = Hexagon::R18; + break; + case Hexagon::R9: + Register = Hexagon::R17; + break; + case Hexagon::R8: + Register = Hexagon::R16; + break; + } +} + +bool HexagonMCChecker::hasValidNewValueDef(const NewSense &Use, + const NewSenseList &Defs) const { + bool Strict = !RelaxNVChecks; + + for (unsigned i = 0, n = Defs.size(); i < n; ++i) { + const NewSense &Def = Defs[i]; + // NVJ cannot use a new FP value [7.6.1] + if (Use.IsNVJ && (Def.IsFloat || Def.PredReg != 0)) + continue; + // If the definition was not predicated, then it does not matter if + // the use is. + if (Def.PredReg == 0) + return true; + // With the strict checks, both the definition and the use must be + // predicated on the same register and condition. + if (Strict) { + if (Def.PredReg == Use.PredReg && Def.Cond == Use.Cond) + return true; + } else { + // With the relaxed checks, if the definition was predicated, the only + // detectable violation is if the use is predicated on the opposing + // condition, otherwise, it's ok. + if (Def.PredReg != Use.PredReg || Def.Cond == Use.Cond) + return true; + } + } + return false; +} + diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h b/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h new file mode 100644 index 00000000000..5fc0bdeaccb --- /dev/null +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCChecker.h @@ -0,0 +1,218 @@ +//===----- HexagonMCChecker.h - Instruction bundle checking ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements the checking of insns inside a bundle according to the +// packet constraint rules of the Hexagon ISA. +// +//===----------------------------------------------------------------------===// + +#ifndef HEXAGONMCCHECKER_H +#define HEXAGONMCCHECKER_H + +#include +#include +#include +#include "MCTargetDesc/HexagonMCShuffler.h" + +using namespace llvm; + +namespace llvm { +class MCOperandInfo; + +typedef struct { + unsigned Error, Warning, ShuffleError; + unsigned Register; +} ErrInfo_T; + +class HexagonMCErrInfo { +public: + enum { + CHECK_SUCCESS = 0, + // Errors. + CHECK_ERROR_BRANCHES = 0x00001, + CHECK_ERROR_NEWP = 0x00002, + CHECK_ERROR_NEWV = 0x00004, + CHECK_ERROR_REGISTERS = 0x00008, + CHECK_ERROR_READONLY = 0x00010, + CHECK_ERROR_LOOP = 0x00020, + CHECK_ERROR_ENDLOOP = 0x00040, + CHECK_ERROR_SOLO = 0x00080, + CHECK_ERROR_SHUFFLE = 0x00100, + CHECK_ERROR_NOSLOTS = 0x00200, + CHECK_ERROR_UNKNOWN = 0x00400, + // Warnings. + CHECK_WARN_CURRENT = 0x10000, + CHECK_WARN_TEMPORARY = 0x20000 + }; + ErrInfo_T s; + + void reset() { + s.Error = CHECK_SUCCESS; + s.Warning = CHECK_SUCCESS; + s.ShuffleError = HexagonShuffler::SHUFFLE_SUCCESS; + s.Register = Hexagon::NoRegister; + }; + HexagonMCErrInfo() { + reset(); + }; + + void setError(unsigned e, unsigned r = Hexagon::NoRegister) + { s.Error = e; s.Register = r; }; + void setWarning(unsigned w, unsigned r = Hexagon::NoRegister) + { s.Warning = w; s.Register = r; }; + void setShuffleError(unsigned e) { s.ShuffleError = e; }; +}; + +/// Check for a valid bundle. +class HexagonMCChecker { + /// Insn bundle. + MCInst& MCB; + MCInst& MCBDX; + const MCRegisterInfo& RI; + MCInstrInfo const &MCII; + MCSubtargetInfo const &STI; + bool bLoadErrInfo; + + /// Set of definitions: register #, if predicated, if predicated true. + typedef std::pair PredSense; + static const PredSense Unconditional; + typedef std::multiset PredSet; + typedef std::multiset::iterator PredSetIterator; + + typedef llvm::DenseMap::iterator DefsIterator; + llvm::DenseMap Defs; + + /// Information about how a new-value register is defined or used: + /// PredReg = predicate register, 0 if use/def not predicated, + /// Cond = true/false for if(PredReg)/if(!PredReg) respectively, + /// IsFloat = true if definition produces a floating point value + /// (not valid for uses), + /// IsNVJ = true if the use is a new-value branch (not valid for + /// definitions). + struct NewSense { + unsigned PredReg; + bool IsFloat, IsNVJ, Cond; + // The special-case "constructors": + static NewSense Jmp(bool isNVJ) { + NewSense NS = { /*PredReg=*/ 0, /*IsFloat=*/ false, /*IsNVJ=*/ isNVJ, + /*Cond=*/ false }; + return NS; + } + static NewSense Use(unsigned PR, bool True) { + NewSense NS = { /*PredReg=*/ PR, /*IsFloat=*/ false, /*IsNVJ=*/ false, + /*Cond=*/ True }; + return NS; + } + static NewSense Def(unsigned PR, bool True, bool Float) { + NewSense NS = { /*PredReg=*/ PR, /*IsFloat=*/ Float, /*IsNVJ=*/ false, + /*Cond=*/ True }; + return NS; + } + }; + /// Set of definitions that produce new register: + typedef llvm::SmallVector NewSenseList; + typedef llvm::DenseMap::iterator NewDefsIterator; + llvm::DenseMap NewDefs; + + /// Set of weak definitions whose clashes should be enforced selectively. + typedef std::set::iterator SoftDefsIterator; + std::set SoftDefs; + + /// Set of current definitions committed to the register file. + typedef std::set::iterator CurDefsIterator; + std::set CurDefs; + + /// Set of temporary definitions not committed to the register file. + typedef std::set::iterator TmpDefsIterator; + std::set TmpDefs; + + /// Set of new predicates used. + typedef std::set::iterator NewPredsIterator; + std::set NewPreds; + + /// Set of predicates defined late. + typedef std::multiset::iterator LatePredsIterator; + std::multiset LatePreds; + + /// Set of uses. + typedef std::set::iterator UsesIterator; + std::set Uses; + + /// Set of new values used: new register, if new-value jump. + typedef llvm::DenseMap::iterator NewUsesIterator; + llvm::DenseMap NewUses; + + /// Pre-defined set of read-only registers. + typedef std::set::iterator ReadOnlyIterator; + std::set ReadOnly; + + std::queue ErrInfoQ; + HexagonMCErrInfo CrntErrInfo; + + void getErrInfo() { + if (bLoadErrInfo == true) { + if (ErrInfoQ.empty()) { + CrntErrInfo.reset(); + } else { + CrntErrInfo.s = ErrInfoQ.front(); + ErrInfoQ.pop(); + } + } + bLoadErrInfo = false; + } + + void init(); + void init(MCInst const&); + + // Checks performed. + bool checkBranches(); + bool checkPredicates(); + bool checkNewValues(); + bool checkRegisters(); + bool checkSolo(); + bool checkShuffle(); + bool checkSlots(); + + static void compoundRegisterMap(unsigned&); + + bool isPredicateRegister(unsigned R) const { + return (Hexagon::P0 == R || Hexagon::P1 == R || + Hexagon::P2 == R || Hexagon::P3 == R); + }; + bool isLoopRegister(unsigned R) const { + return (Hexagon::SA0 == R || Hexagon::LC0 == R || + Hexagon::SA1 == R || Hexagon::LC1 == R); + }; + + bool hasValidNewValueDef(const NewSense &Use, + const NewSenseList &Defs) const; + + public: + explicit HexagonMCChecker(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, MCInst& mcb, MCInst &mcbdx, + const MCRegisterInfo& ri); + + bool check(); + + /// add a new error/warning + void addErrInfo(HexagonMCErrInfo &err) { ErrInfoQ.push(err.s); }; + + /// Return the error code for the last operation in the insn bundle. + unsigned getError() { getErrInfo(); return CrntErrInfo.s.Error; }; + unsigned getWarning() { getErrInfo(); return CrntErrInfo.s.Warning; }; + unsigned getShuffleError() { getErrInfo(); return CrntErrInfo.s.ShuffleError; }; + unsigned getErrRegister() { getErrInfo(); return CrntErrInfo.s.Register; }; + bool getNextErrInfo() { + bLoadErrInfo = true; + return (ErrInfoQ.empty()) ? false : (getErrInfo(), true); + } +}; + +} + +#endif // HEXAGONMCCHECKER_H diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp index 716165ffb74..34817cd98f2 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp @@ -195,15 +195,13 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { // Special case this one from Group L2. // Rd = memw(r29+#u5:2) if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg)) { - if (HexagonMCInstrInfo::isIntReg(SrcReg) && Hexagon::R29 == SrcReg && - MCI.getOperand(2).isImm() && - isShiftedUInt<5, 2>(MCI.getOperand(2).getImm())) { + if (HexagonMCInstrInfo::isIntReg(SrcReg) && + Hexagon::R29 == SrcReg && inRange<5, 2>(MCI, 2)) { return HexagonII::HSIG_L2; } // Rd = memw(Rs+#u4:2) if (HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) && - (MCI.getOperand(2).isImm() && - isShiftedUInt<4, 2>(MCI.getOperand(2).getImm()))) { + inRange<4, 2>(MCI, 2)) { return HexagonII::HSIG_L1; } } @@ -214,7 +212,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { SrcReg = MCI.getOperand(1).getReg(); if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) && HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) && - MCI.getOperand(2).isImm() && isUInt<4>(MCI.getOperand(2).getImm())) { + inRange<4>(MCI, 2)) { return HexagonII::HSIG_L1; } break; @@ -235,8 +233,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { SrcReg = MCI.getOperand(1).getReg(); if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) && HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) && - MCI.getOperand(2).isImm() && - isShiftedUInt<3, 1>(MCI.getOperand(2).getImm())) { + inRange<3, 1>(MCI, 2)) { return HexagonII::HSIG_L2; } break; @@ -246,7 +243,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { SrcReg = MCI.getOperand(1).getReg(); if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) && HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) && - MCI.getOperand(2).isImm() && isUInt<3>(MCI.getOperand(2).getImm())) { + inRange<3>(MCI, 2)) { return HexagonII::HSIG_L2; } break; @@ -256,8 +253,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { SrcReg = MCI.getOperand(1).getReg(); if (HexagonMCInstrInfo::isDblRegForSubInst(DstReg) && HexagonMCInstrInfo::isIntReg(SrcReg) && Hexagon::R29 == SrcReg && - MCI.getOperand(2).isImm() && - isShiftedUInt<5, 3>(MCI.getOperand(2).getImm())) { + inRange<5, 3>(MCI, 2)) { return HexagonII::HSIG_L2; } break; @@ -326,15 +322,13 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { Src2Reg = MCI.getOperand(2).getReg(); if (HexagonMCInstrInfo::isIntReg(Src1Reg) && HexagonMCInstrInfo::isIntRegForSubInst(Src2Reg) && - Hexagon::R29 == Src1Reg && MCI.getOperand(1).isImm() && - isShiftedUInt<5, 2>(MCI.getOperand(1).getImm())) { + Hexagon::R29 == Src1Reg && inRange<5, 2>(MCI, 1)) { return HexagonII::HSIG_S2; } // memw(Rs+#u4:2) = Rt if (HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) && HexagonMCInstrInfo::isIntRegForSubInst(Src2Reg) && - MCI.getOperand(1).isImm() && - isShiftedUInt<4, 2>(MCI.getOperand(1).getImm())) { + inRange<4, 2>(MCI, 1)) { return HexagonII::HSIG_S1; } break; @@ -344,7 +338,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { Src2Reg = MCI.getOperand(2).getReg(); if (HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) && HexagonMCInstrInfo::isIntRegForSubInst(Src2Reg) && - MCI.getOperand(1).isImm() && isUInt<4>(MCI.getOperand(1).getImm())) { + inRange<4>(MCI, 1)) { return HexagonII::HSIG_S1; } break; @@ -363,8 +357,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { Src2Reg = MCI.getOperand(2).getReg(); if (HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) && HexagonMCInstrInfo::isIntRegForSubInst(Src2Reg) && - MCI.getOperand(1).isImm() && - isShiftedUInt<3, 1>(MCI.getOperand(1).getImm())) { + inRange<3, 1>(MCI, 1)) { return HexagonII::HSIG_S2; } break; @@ -374,8 +367,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { Src2Reg = MCI.getOperand(2).getReg(); if (HexagonMCInstrInfo::isDblRegForSubInst(Src2Reg) && HexagonMCInstrInfo::isIntReg(Src1Reg) && Hexagon::R29 == Src1Reg && - MCI.getOperand(1).isImm() && - isShiftedInt<6, 3>(MCI.getOperand(1).getImm())) { + inSRange<6, 3>(MCI, 1)) { return HexagonII::HSIG_S2; } break; @@ -383,9 +375,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { // memw(Rs+#u4:2) = #U1 Src1Reg = MCI.getOperand(0).getReg(); if (HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) && - MCI.getOperand(1).isImm() && - isShiftedUInt<4, 2>(MCI.getOperand(1).getImm()) && - MCI.getOperand(2).isImm() && isUInt<1>(MCI.getOperand(2).getImm())) { + inRange<4, 2>(MCI, 1) && inRange<1>(MCI, 2)) { return HexagonII::HSIG_S2; } break; @@ -393,16 +383,13 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { // memb(Rs+#u4) = #U1 Src1Reg = MCI.getOperand(0).getReg(); if (HexagonMCInstrInfo::isIntRegForSubInst(Src1Reg) && - MCI.getOperand(1).isImm() && isUInt<4>(MCI.getOperand(1).getImm()) && - MCI.getOperand(2).isImm() && isUInt<1>(MCI.getOperand(2).getImm())) { + inRange<4>(MCI, 1) && inRange<1>(MCI, 2)) { return HexagonII::HSIG_S2; } break; case Hexagon::S2_allocframe: - if (MCI.getOperand(0).isImm() && - isShiftedUInt<5, 3>(MCI.getOperand(0).getImm())) { + if (inRange<5, 3>(MCI, 0)) return HexagonII::HSIG_S2; - } break; // // Group A: @@ -428,8 +415,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg)) { // Rd = add(r29,#u6:2) if (HexagonMCInstrInfo::isIntReg(SrcReg) && Hexagon::R29 == SrcReg && - MCI.getOperand(2).isImm() && - isShiftedUInt<6, 2>(MCI.getOperand(2).getImm())) { + inRange<6, 2>(MCI, 2)) { return HexagonII::HSIG_A; } // Rx = add(Rx,#s7) @@ -439,8 +425,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { // Rd = add(Rs,#1) // Rd = add(Rs,#-1) if (HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) && - MCI.getOperand(2).isImm() && ((MCI.getOperand(2).getImm() == 1) || - (MCI.getOperand(2).getImm() == -1))) { + (minConstant(MCI, 2) == 1 || minConstant(MCI, 2) == -1)) { return HexagonII::HSIG_A; } } @@ -460,8 +445,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { SrcReg = MCI.getOperand(1).getReg(); if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) && HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) && - MCI.getOperand(2).isImm() && ((MCI.getOperand(2).getImm() == 1) || - (MCI.getOperand(2).getImm() == 255))) { + (minConstant(MCI, 2) == 1 || minConstant(MCI, 2) == 255)) { return HexagonII::HSIG_A; } break; @@ -491,8 +475,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { DstReg = MCI.getOperand(0).getReg(); // Rd PredReg = MCI.getOperand(1).getReg(); // P0 if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg) && - Hexagon::P0 == PredReg && MCI.getOperand(2).isImm() && - MCI.getOperand(2).getImm() == 0) { + Hexagon::P0 == PredReg && minConstant(MCI, 2) == 0) { return HexagonII::HSIG_A; } break; @@ -502,7 +485,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { SrcReg = MCI.getOperand(1).getReg(); if (Hexagon::P0 == DstReg && HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) && - MCI.getOperand(2).isImm() && isUInt<2>(MCI.getOperand(2).getImm())) { + inRange<2>(MCI, 2)) { return HexagonII::HSIG_A; } break; @@ -511,10 +494,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { // Rdd = combine(#u2,#U2) DstReg = MCI.getOperand(0).getReg(); if (HexagonMCInstrInfo::isDblRegForSubInst(DstReg) && - // TODO: Handle Globals/Symbols - (MCI.getOperand(1).isImm() && isUInt<2>(MCI.getOperand(1).getImm())) && - ((MCI.getOperand(2).isImm() && - isUInt<2>(MCI.getOperand(2).getImm())))) { + inRange<2>(MCI, 1) && inRange<2>(MCI, 2)) { return HexagonII::HSIG_A; } break; @@ -524,7 +504,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { SrcReg = MCI.getOperand(1).getReg(); if (HexagonMCInstrInfo::isDblRegForSubInst(DstReg) && HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) && - (MCI.getOperand(2).isImm() && MCI.getOperand(2).getImm() == 0)) { + minConstant(MCI, 2) == 0) { return HexagonII::HSIG_A; } break; @@ -534,7 +514,7 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { SrcReg = MCI.getOperand(2).getReg(); if (HexagonMCInstrInfo::isDblRegForSubInst(DstReg) && HexagonMCInstrInfo::isIntRegForSubInst(SrcReg) && - (MCI.getOperand(1).isImm() && MCI.getOperand(1).getImm() == 0)) { + minConstant(MCI, 1) == 0) { return HexagonII::HSIG_A; } break; @@ -556,19 +536,17 @@ unsigned HexagonMCInstrInfo::getDuplexCandidateGroup(MCInst const &MCI) { } bool HexagonMCInstrInfo::subInstWouldBeExtended(MCInst const &potentialDuplex) { - unsigned DstReg, SrcReg; - switch (potentialDuplex.getOpcode()) { case Hexagon::A2_addi: // testing for case of: Rx = add(Rx,#s7) DstReg = potentialDuplex.getOperand(0).getReg(); SrcReg = potentialDuplex.getOperand(1).getReg(); if (DstReg == SrcReg && HexagonMCInstrInfo::isIntRegForSubInst(DstReg)) { - if (potentialDuplex.getOperand(2).isExpr()) + int64_t Value; + if (!potentialDuplex.getOperand(2).getExpr()->evaluateAsAbsolute(Value)) return true; - if (potentialDuplex.getOperand(2).isImm() && - !(isShiftedInt<7, 0>(potentialDuplex.getOperand(2).getImm()))) + if (!isShiftedInt<7, 0>(Value)) return true; } break; @@ -576,15 +554,14 @@ bool HexagonMCInstrInfo::subInstWouldBeExtended(MCInst const &potentialDuplex) { DstReg = potentialDuplex.getOperand(0).getReg(); if (HexagonMCInstrInfo::isIntRegForSubInst(DstReg)) { - if (potentialDuplex.getOperand(1).isExpr()) + int64_t Value; + if (!potentialDuplex.getOperand(1).getExpr()->evaluateAsAbsolute(Value)) return true; // Check for case of Rd = #-1. - if (potentialDuplex.getOperand(1).isImm() && - (potentialDuplex.getOperand(1).getImm() == -1)) + if (Value == -1) return false; // Check for case of Rd = #u6. - if (potentialDuplex.getOperand(1).isImm() && - !isShiftedUInt<6, 0>(potentialDuplex.getOperand(1).getImm())) + if (!isShiftedUInt<6, 0>(Value)) return true; } break; @@ -712,19 +689,23 @@ inline static void addOps(MCInst &subInstPtr, MCInst const &Inst, MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) { MCInst Result; + bool Absolute; + int64_t Value; switch (Inst.getOpcode()) { default: // dbgs() << "opcode: "<< Inst->getOpcode() << "\n"; llvm_unreachable("Unimplemented subinstruction \n"); break; case Hexagon::A2_addi: - if (Inst.getOperand(2).isImm() && Inst.getOperand(2).getImm() == 1) { + Absolute = Inst.getOperand(2).getExpr()->evaluateAsAbsolute(Value); + assert(Absolute);(void)Absolute; + if (Value == 1) { Result.setOpcode(Hexagon::V4_SA1_inc); addOps(Result, Inst, 0); addOps(Result, Inst, 1); break; } // 1,2 SUBInst $Rd = add($Rs, #1) - else if (Inst.getOperand(2).isImm() && Inst.getOperand(2).getImm() == -1) { + else if (Value == -1) { Result.setOpcode(Hexagon::V4_SA1_dec); addOps(Result, Inst, 0); addOps(Result, Inst, 1); @@ -754,7 +735,7 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) { addOps(Result, Inst, 0); break; // 1 SUBInst allocframe(#$u5_3) case Hexagon::A2_andir: - if (Inst.getOperand(2).getImm() == 255) { + if (minConstant(Inst, 2) == 255) { Result.setOpcode(Hexagon::V4_SA1_zxtb); addOps(Result, Inst, 0); addOps(Result, Inst, 1); @@ -772,26 +753,27 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) { break; // 2,3 SUBInst p0 = cmp.eq($Rs, #$u2) case Hexagon::A4_combineii: case Hexagon::A2_combineii: - if (Inst.getOperand(1).getImm() == 1) { + Absolute = Inst.getOperand(1).getExpr()->evaluateAsAbsolute(Value); + assert(Absolute);(void)Absolute; + if (Value == 1) { Result.setOpcode(Hexagon::V4_SA1_combine1i); addOps(Result, Inst, 0); addOps(Result, Inst, 2); break; // 1,3 SUBInst $Rdd = combine(#1, #$u2) } - - if (Inst.getOperand(1).getImm() == 3) { + if (Value == 3) { Result.setOpcode(Hexagon::V4_SA1_combine3i); addOps(Result, Inst, 0); addOps(Result, Inst, 2); break; // 1,3 SUBInst $Rdd = combine(#3, #$u2) } - if (Inst.getOperand(1).getImm() == 0) { + if (Value == 0) { Result.setOpcode(Hexagon::V4_SA1_combine0i); addOps(Result, Inst, 0); addOps(Result, Inst, 2); break; // 1,3 SUBInst $Rdd = combine(#0, #$u2) } - if (Inst.getOperand(1).getImm() == 2) { + if (Value == 2) { Result.setOpcode(Hexagon::V4_SA1_combine2i); addOps(Result, Inst, 0); addOps(Result, Inst, 2); @@ -894,12 +876,14 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) { break; // 1,2,3 SUBInst $Rd = memw($Rs + #$u4_2) } case Hexagon::S4_storeirb_io: - if (Inst.getOperand(2).getImm() == 0) { + Absolute = Inst.getOperand(2).getExpr()->evaluateAsAbsolute(Value); + assert(Absolute);(void)Absolute; + if (Value == 0) { Result.setOpcode(Hexagon::V4_SS2_storebi0); addOps(Result, Inst, 0); addOps(Result, Inst, 1); break; // 1,2 SUBInst memb($Rs + #$u4_0)=#0 - } else if (Inst.getOperand(2).getImm() == 1) { + } else if (Value == 1) { Result.setOpcode(Hexagon::V4_SS2_storebi1); addOps(Result, Inst, 0); addOps(Result, Inst, 1); @@ -923,12 +907,14 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) { addOps(Result, Inst, 2); break; // 1,2,3 SUBInst memb($Rs + #$u4_0) = $Rt case Hexagon::S4_storeiri_io: - if (Inst.getOperand(2).getImm() == 0) { + Absolute = Inst.getOperand(2).getExpr()->evaluateAsAbsolute(Value); + assert(Absolute);(void)Absolute; + if (Value == 0) { Result.setOpcode(Hexagon::V4_SS2_storewi0); addOps(Result, Inst, 0); addOps(Result, Inst, 1); break; // 3 1,2 SUBInst memw($Rs + #$u4_2)=#0 - } else if (Inst.getOperand(2).getImm() == 1) { + } else if (Value == 1) { Result.setOpcode(Hexagon::V4_SS2_storewi1); addOps(Result, Inst, 0); addOps(Result, Inst, 1); @@ -983,7 +969,8 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) { addOps(Result, Inst, 0); break; // 2 SUBInst if (p0) $Rd = #0 case Hexagon::A2_tfrsi: - if (Inst.getOperand(1).isImm() && Inst.getOperand(1).getImm() == -1) { + Absolute = Inst.getOperand(1).getExpr()->evaluateAsAbsolute(Value); + if (Absolute && Value == -1) { Result.setOpcode(Hexagon::V4_SA1_setin1); addOps(Result, Inst, 0); break; // 2 1 SUBInst $Rd = #-1 @@ -1044,6 +1031,8 @@ HexagonMCInstrInfo::getDuplexPossibilties(MCInstrInfo const &MCII, << "\n"); bisReversable = false; } + if (HexagonMCInstrInfo::isMemReorderDisabled(MCB)) // }:mem_noshuf + bisReversable = false; // Try in order. if (isOrderedDuplexPair( diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.cpp new file mode 100644 index 00000000000..fc626265751 --- /dev/null +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.cpp @@ -0,0 +1,49 @@ +//===-- HexagonMCExpr.cpp - Hexagon specific MC expression classes +//----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "HexagonMCExpr.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "hexagon-mcexpr" + +HexagonNoExtendOperand *HexagonNoExtendOperand::Create(MCExpr const *Expr, + MCContext &Ctx) { + return new (Ctx) HexagonNoExtendOperand(Expr); +} + +bool HexagonNoExtendOperand::evaluateAsRelocatableImpl( + MCValue &Res, MCAsmLayout const *Layout, MCFixup const *Fixup) const { + return Expr->evaluateAsRelocatable(Res, Layout, Fixup); +} + +void HexagonNoExtendOperand::visitUsedExpr(MCStreamer &Streamer) const {} + +MCFragment *llvm::HexagonNoExtendOperand::findAssociatedFragment() const { + return Expr->findAssociatedFragment(); +} + +void HexagonNoExtendOperand::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {} + +MCExpr const *HexagonNoExtendOperand::getExpr() const { return Expr; } + +bool HexagonNoExtendOperand::classof(MCExpr const *E) { + return E->getKind() == MCExpr::Target; +} + +HexagonNoExtendOperand::HexagonNoExtendOperand(MCExpr const *Expr) + : Expr(Expr) {} + +void HexagonNoExtendOperand::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { + Expr->print(OS, MAI); +} diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.h b/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.h new file mode 100644 index 00000000000..60f180fb2bc --- /dev/null +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCExpr.h @@ -0,0 +1,35 @@ +//==- HexagonMCExpr.h - Hexagon specific MC expression classes --*- 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_HEXAGON_HEXAGONMCEXPR_H +#define LLVM_LIB_TARGET_HEXAGON_HEXAGONMCEXPR_H + +#include "llvm/MC/MCExpr.h" + +namespace llvm { +class MCInst; +class HexagonNoExtendOperand : public MCTargetExpr { +public: + static HexagonNoExtendOperand *Create(MCExpr const *Expr, MCContext &Ctx); + void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; + bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, + const MCFixup *Fixup) const override; + void visitUsedExpr(MCStreamer &Streamer) const override; + MCFragment *findAssociatedFragment() const override; + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override; + static bool classof(MCExpr const *E); + MCExpr const *getExpr() const; + +private: + HexagonNoExtendOperand(MCExpr const *Expr); + MCExpr const *Expr; +}; +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONMCEXPR_H diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp index 48b15f85a78..db338ab5e60 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.cpp @@ -15,12 +15,32 @@ #include "Hexagon.h" #include "HexagonBaseInfo.h" +#include "HexagonMCChecker.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCSubtargetInfo.h" namespace llvm { +void HexagonMCInstrInfo::addConstant(MCInst &MI, uint64_t Value, + MCContext &Context) { + MI.addOperand(MCOperand::createExpr(MCConstantExpr::create(Value, Context))); +} + +void HexagonMCInstrInfo::addConstExtender(MCInstrInfo const &MCII, MCInst &MCB, + MCInst const &MCI) { + assert(HexagonMCInstrInfo::isBundle(MCB)); + MCOperand const &exOp = + MCI.getOperand(HexagonMCInstrInfo::getExtendableOp(MCII, MCI)); + + // Create the extender. + MCInst *XMCI = + new MCInst(HexagonMCInstrInfo::deriveExtender(MCII, MCI, exOp)); + + MCB.addOperand(MCOperand::createInst(XMCI)); +} + iterator_range HexagonMCInstrInfo::bundleInstructions(MCInst const &MCI) { assert(isBundle(MCI)); @@ -35,6 +55,38 @@ size_t HexagonMCInstrInfo::bundleSize(MCInst const &MCI) { return (1); } +bool HexagonMCInstrInfo::canonicalizePacket(MCInstrInfo const &MCII, + MCSubtargetInfo const &STI, + MCContext &Context, MCInst &MCB, + HexagonMCChecker *Check) { + // Examine the packet and convert pairs of instructions to compound + // instructions when possible. + if (!HexagonDisableCompound) + HexagonMCInstrInfo::tryCompound(MCII, Context, MCB); + // Check the bundle for errors. + bool CheckOk = Check ? Check->check() : true; + if (!CheckOk) + return false; + HexagonMCShuffle(MCII, STI, MCB); + // Examine the packet and convert pairs of instructions to duplex + // instructions when possible. + MCInst InstBundlePreDuplex = MCInst(MCB); + if (!HexagonDisableDuplex) { + SmallVector possibleDuplexes; + possibleDuplexes = HexagonMCInstrInfo::getDuplexPossibilties(MCII, MCB); + HexagonMCShuffle(MCII, STI, Context, MCB, possibleDuplexes); + } + // Examines packet and pad the packet, if needed, when an + // end-loop is in the bundle. + HexagonMCInstrInfo::padEndloop(MCB); + // If compounding and duplexing didn't reduce the size below + // 4 or less we have a packet that is too big. + if (HexagonMCInstrInfo::bundleSize(MCB) > HEXAGON_PACKET_SIZE) + return false; + HexagonMCShuffle(MCII, STI, MCB); + return true; +} + void HexagonMCInstrInfo::clampExtended(MCInstrInfo const &MCII, MCInst &MCI) { assert(HexagonMCInstrInfo::isExtendable(MCII, MCI) || HexagonMCInstrInfo::isExtended(MCII, MCI)); @@ -64,6 +116,27 @@ MCInst *HexagonMCInstrInfo::deriveDuplex(MCContext &Context, unsigned iClass, return duplexInst; } +MCInst HexagonMCInstrInfo::deriveExtender(MCInstrInfo const &MCII, + MCInst const &Inst, + MCOperand const &MO) { + assert(HexagonMCInstrInfo::isExtendable(MCII, Inst) || + HexagonMCInstrInfo::isExtended(MCII, Inst)); + + MCInstrDesc const &Desc = HexagonMCInstrInfo::getDesc(MCII, Inst); + MCInst XMI; + XMI.setOpcode((Desc.isBranch() || Desc.isCall() || + HexagonMCInstrInfo::getType(MCII, Inst) == HexagonII::TypeCR) + ? Hexagon::A4_ext_b + : Hexagon::A4_ext); + if (MO.isImm()) + XMI.addOperand(MCOperand::createImm(MO.getImm() & (~0x3f))); + else if (MO.isExpr()) + XMI.addOperand(MCOperand::createExpr(MO.getExpr())); + else + llvm_unreachable("invalid extendable operand"); + return XMI; +} + MCInst const *HexagonMCInstrInfo::extenderForIndex(MCInst const &MCB, size_t Index) { assert(Index <= bundleSize(MCB)); @@ -76,6 +149,12 @@ MCInst const *HexagonMCInstrInfo::extenderForIndex(MCInst const &MCB, return nullptr; } +void HexagonMCInstrInfo::extendIfNeeded(MCInstrInfo const &MCII, MCInst &MCB, + MCInst const &MCI, bool MustExtend) { + if (isConstExtended(MCII, MCI) || MustExtend) + addConstExtender(MCII, MCB, MCI); +} + HexagonII::MemAccessSize HexagonMCInstrInfo::getAccessSize(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; @@ -186,6 +265,25 @@ MCOperand const &HexagonMCInstrInfo::getNewValueOperand(MCInstrInfo const &MCII, return (MCO); } +/// Return the new value or the newly produced value. +unsigned short HexagonMCInstrInfo::getNewValueOp2(MCInstrInfo const &MCII, + MCInst const &MCI) { + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return ((F >> HexagonII::NewValueOpPos2) & HexagonII::NewValueOpMask2); +} + +MCOperand const & +HexagonMCInstrInfo::getNewValueOperand2(MCInstrInfo const &MCII, + MCInst const &MCI) { + unsigned O = HexagonMCInstrInfo::getNewValueOp2(MCII, MCI); + MCOperand const &MCO = MCI.getOperand(O); + + assert((HexagonMCInstrInfo::isNewValue(MCII, MCI) || + HexagonMCInstrInfo::hasNewValue2(MCII, MCI)) && + MCO.isReg()); + return (MCO); +} + int HexagonMCInstrInfo::getSubTarget(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; @@ -242,6 +340,13 @@ bool HexagonMCInstrInfo::hasNewValue(MCInstrInfo const &MCII, return ((F >> HexagonII::hasNewValuePos) & HexagonII::hasNewValueMask); } +/// Return whether the insn produces a second value. +bool HexagonMCInstrInfo::hasNewValue2(MCInstrInfo const &MCII, + MCInst const &MCI) { + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return ((F >> HexagonII::hasNewValuePos2) & HexagonII::hasNewValueMask2); +} + MCInst const &HexagonMCInstrInfo::instruction(MCInst const &MCB, size_t Index) { assert(isBundle(MCB)); assert(Index < HEXAGON_PACKET_SIZE); @@ -261,6 +366,11 @@ bool HexagonMCInstrInfo::isCanon(MCInstrInfo const &MCII, MCInst const &MCI) { HexagonMCInstrInfo::getType(MCII, MCI) != HexagonII::TypeENDLOOP); } +bool HexagonMCInstrInfo::isCompound(MCInstrInfo const &MCII, + MCInst const &MCI) { + return (getType(MCII, MCI) == HexagonII::TypeCOMPOUND); +} + bool HexagonMCInstrInfo::isDblRegForSubInst(unsigned Reg) { return ((Reg >= Hexagon::D0 && Reg <= Hexagon::D3) || (Reg >= Hexagon::D8 && Reg <= Hexagon::D11)); @@ -282,14 +392,21 @@ bool HexagonMCInstrInfo::isConstExtended(MCInstrInfo const &MCII, MCInst const &MCI) { if (HexagonMCInstrInfo::isExtended(MCII, MCI)) return true; - - if (!HexagonMCInstrInfo::isExtendable(MCII, MCI)) + // Branch insns are handled as necessary by relaxation. + if ((HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeJ) || + (HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCOMPOUND && + HexagonMCInstrInfo::getDesc(MCII, MCI).isBranch()) || + (HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeNV && + HexagonMCInstrInfo::getDesc(MCII, MCI).isBranch())) + return false; + // Otherwise loop instructions and other CR insts are handled by relaxation + else if ((HexagonMCInstrInfo::getType(MCII, MCI) == HexagonII::TypeCR) && + (MCI.getOpcode() != Hexagon::C4_addipc)) + return false; + else if (!HexagonMCInstrInfo::isExtendable(MCII, MCI)) return false; - short ExtOpNum = HexagonMCInstrInfo::getCExtOpNum(MCII, MCI); - int MinValue = HexagonMCInstrInfo::getMinValue(MCII, MCI); - int MaxValue = HexagonMCInstrInfo::getMaxValue(MCII, MCI); - MCOperand const &MO = MCI.getOperand(ExtOpNum); + MCOperand const &MO = HexagonMCInstrInfo::getExtendableOperand(MCII, MCI); // We could be using an instruction with an extendable immediate and shoehorn // a global address into it. If it is a global address it will be constant @@ -297,15 +414,13 @@ bool HexagonMCInstrInfo::isConstExtended(MCInstrInfo const &MCII, // We currently only handle isGlobal() because it is the only kind of // object we are going to end up with here for now. // In the future we probably should add isSymbol(), etc. - if (MO.isExpr()) + assert(!MO.isImm()); + int64_t Value; + if (!MO.getExpr()->evaluateAsAbsolute(Value)) return true; - - // If the extendable operand is not 'Immediate' type, the instruction should - // have 'isExtended' flag set. - assert(MO.isImm() && "Extendable operand must be Immediate type"); - - int ImmValue = MO.getImm(); - return (ImmValue < MinValue || ImmValue > MaxValue); + int MinValue = HexagonMCInstrInfo::getMinValue(MCII, MCI); + int MaxValue = HexagonMCInstrInfo::getMaxValue(MCII, MCI); + return (MinValue > Value || Value > MaxValue); } bool HexagonMCInstrInfo::isExtendable(MCInstrInfo const &MCII, @@ -374,6 +489,19 @@ bool HexagonMCInstrInfo::isPredicated(MCInstrInfo const &MCII, return ((F >> HexagonII::PredicatedPos) & HexagonII::PredicatedMask); } +bool HexagonMCInstrInfo::isPredicateLate(MCInstrInfo const &MCII, + MCInst const &MCI) { + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return (F >> HexagonII::PredicateLatePos & HexagonII::PredicateLateMask); +} + +/// Return whether the insn is newly predicated. +bool HexagonMCInstrInfo::isPredicatedNew(MCInstrInfo const &MCII, + MCInst const &MCI) { + const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; + return ((F >> HexagonII::PredicatedNewPos) & HexagonII::PredicatedNewMask); +} + bool HexagonMCInstrInfo::isPredicatedTrue(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; @@ -394,6 +522,18 @@ bool HexagonMCInstrInfo::isSolo(MCInstrInfo const &MCII, MCInst const &MCI) { return ((F >> HexagonII::SoloPos) & HexagonII::SoloMask); } +bool HexagonMCInstrInfo::isMemReorderDisabled(MCInst const &MCI) { + assert(isBundle(MCI)); + auto Flags = MCI.getOperand(0).getImm(); + return (Flags & memReorderDisabledMask) != 0; +} + +bool HexagonMCInstrInfo::isMemStoreReorderEnabled(MCInst const &MCI) { + assert(isBundle(MCI)); + auto Flags = MCI.getOperand(0).getImm(); + return (Flags & memStoreReorderEnabledMask) != 0; +} + bool HexagonMCInstrInfo::isSoloAX(MCInstrInfo const &MCII, MCInst const &MCI) { const uint64_t F = HexagonMCInstrInfo::getDesc(MCII, MCI).TSFlags; return ((F >> HexagonII::SoloAXPos) & HexagonII::SoloAXMask); @@ -405,6 +545,27 @@ bool HexagonMCInstrInfo::isSoloAin1(MCInstrInfo const &MCII, return ((F >> HexagonII::SoloAin1Pos) & HexagonII::SoloAin1Mask); } +bool HexagonMCInstrInfo::isVector(MCInstrInfo const &MCII, MCInst const &MCI) { + if ((getType(MCII, MCI) <= HexagonII::TypeCVI_LAST) && + (getType(MCII, MCI) >= HexagonII::TypeCVI_FIRST)) + return true; + return false; +} + +int64_t HexagonMCInstrInfo::minConstant(MCInst const &MCI, size_t Index) { + auto Sentinal = static_cast(std::numeric_limits::max()) + << 8; + if (MCI.size() <= Index) + return Sentinal; + MCOperand const &MCO = MCI.getOperand(Index); + if (!MCO.isExpr()) + return Sentinal; + int64_t Value; + if (!MCO.getExpr()->evaluateAsAbsolute(Value)) + return Sentinal; + return Value; +} + void HexagonMCInstrInfo::padEndloop(MCInst &MCB) { MCInst Nop; Nop.setOpcode(Hexagon::A2_nop); @@ -456,6 +617,20 @@ void HexagonMCInstrInfo::setInnerLoop(MCInst &MCI) { Operand.setImm(Operand.getImm() | innerLoopMask); } +void HexagonMCInstrInfo::setMemReorderDisabled(MCInst &MCI) { + assert(isBundle(MCI)); + MCOperand &Operand = MCI.getOperand(0); + Operand.setImm(Operand.getImm() | memReorderDisabledMask); + assert(isMemReorderDisabled(MCI)); +} + +void HexagonMCInstrInfo::setMemStoreReorderEnabled(MCInst &MCI) { + assert(isBundle(MCI)); + MCOperand &Operand = MCI.getOperand(0); + Operand.setImm(Operand.getImm() | memStoreReorderEnabledMask); + assert(isMemStoreReorderEnabled(MCI)); +} + void HexagonMCInstrInfo::setOuterLoop(MCInst &MCI) { assert(isBundle(MCI)); MCOperand &Operand = MCI.getOperand(0); diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h b/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h index 32d61a4a7be..452abebc948 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCInstrInfo.h @@ -14,9 +14,11 @@ #ifndef LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCINSTRINFO_H #define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONMCINSTRINFO_H +#include "HexagonMCExpr.h" #include "llvm/MC/MCInst.h" namespace llvm { +class HexagonMCChecker; class MCContext; class MCInstrDesc; class MCInstrInfo; @@ -39,20 +41,44 @@ int64_t const innerLoopMask = 1 << innerLoopOffset; size_t const outerLoopOffset = 1; int64_t const outerLoopMask = 1 << outerLoopOffset; +// do not reorder memory load/stores by default load/stores are re-ordered +// and by default loads can be re-ordered +size_t const memReorderDisabledOffset = 2; +int64_t const memReorderDisabledMask = 1 << memReorderDisabledOffset; + +// allow re-ordering of memory stores by default stores cannot be re-ordered +size_t const memStoreReorderEnabledOffset = 3; +int64_t const memStoreReorderEnabledMask = 1 << memStoreReorderEnabledOffset; + size_t const bundleInstructionsOffset = 1; +void addConstant(MCInst &MI, uint64_t Value, MCContext &Context); +void addConstExtender(MCInstrInfo const &MCII, MCInst &MCB, MCInst const &MCI); + // Returns a iterator range of instructions in this bundle iterator_range bundleInstructions(MCInst const &MCI); // Returns the number of instructions in the bundle size_t bundleSize(MCInst const &MCI); +// Put the packet in to canonical form, compound, duplex, pad, and shuffle +bool canonicalizePacket(MCInstrInfo const &MCII, MCSubtargetInfo const &STI, + MCContext &Context, MCInst &MCB, + HexagonMCChecker *Checker); + // Clamp off upper 26 bits of extendable operand for emission void clampExtended(MCInstrInfo const &MCII, MCInst &MCI); +// Return the extender for instruction at Index or nullptr if none +MCInst const *extenderForIndex(MCInst const &MCB, size_t Index); +void extendIfNeeded(MCInstrInfo const &MCII, MCInst &MCB, MCInst const &MCI, + bool MustExtend); + // Create a duplex instruction given the two subinsts MCInst *deriveDuplex(MCContext &Context, unsigned iClass, MCInst const &inst0, MCInst const &inst1); +MCInst deriveExtender(MCInstrInfo const &MCII, MCInst const &Inst, + MCOperand const &MO); // Convert this instruction in to a duplex subinst MCInst deriveSubInst(MCInst const &Inst); @@ -108,6 +134,9 @@ unsigned short getNewValueOp(MCInstrInfo const &MCII, MCInst const &MCI); // Return the operand that consumes or produces a new value. MCOperand const &getNewValueOperand(MCInstrInfo const &MCII, MCInst const &MCI); +unsigned short getNewValueOp2(MCInstrInfo const &MCII, MCInst const &MCI); +MCOperand const &getNewValueOperand2(MCInstrInfo const &MCII, + MCInst const &MCI); int getSubTarget(MCInstrInfo const &MCII, MCInst const &MCI); @@ -125,6 +154,7 @@ bool hasImmExt(MCInst const &MCI); // Return whether the instruction is a legal new-value producer. bool hasNewValue(MCInstrInfo const &MCII, MCInst const &MCI); +bool hasNewValue2(MCInstrInfo const &MCII, MCInst const &MCI); // Return the instruction at Index MCInst const &instruction(MCInst const &MCB, size_t Index); @@ -134,10 +164,24 @@ bool isBundle(MCInst const &MCI); // Return whether the insn is an actual insn. bool isCanon(MCInstrInfo const &MCII, MCInst const &MCI); +bool isCompound(MCInstrInfo const &MCII, MCInst const &MCI); // Return the duplex iclass given the two duplex classes unsigned iClassOfDuplexPair(unsigned Ga, unsigned Gb); +int64_t minConstant(MCInst const &MCI, size_t Index); +template +bool inRange(MCInst const &MCI, size_t Index) { + return isShiftedUInt(minConstant(MCI, Index)); +} +template +bool inSRange(MCInst const &MCI, size_t Index) { + return isShiftedInt(minConstant(MCI, Index)); +} +template bool inRange(MCInst const &MCI, size_t Index) { + return isUInt(minConstant(MCI, Index)); +} + // Return whether the instruction needs to be constant extended. bool isConstExtended(MCInstrInfo const &MCII, MCInst const &MCI); @@ -173,6 +217,8 @@ bool isIntReg(unsigned Reg); // Is this register suitable for use in a duplex subinst bool isIntRegForSubInst(unsigned Reg); +bool isMemReorderDisabled(MCInst const &MCI); +bool isMemStoreReorderEnabled(MCInst const &MCI); // Return whether the insn is a new-value consumer. bool isNewValue(MCInstrInfo const &MCII, MCInst const &MCI); @@ -191,6 +237,8 @@ bool isOuterLoop(MCInst const &MCI); // Return whether this instruction is predicated bool isPredicated(MCInstrInfo const &MCII, MCInst const &MCI); +bool isPredicateLate(MCInstrInfo const &MCII, MCInst const &MCI); +bool isPredicatedNew(MCInstrInfo const &MCII, MCInst const &MCI); // Return whether the predicate sense is true bool isPredicatedTrue(MCInstrInfo const &MCII, MCInst const &MCI); @@ -209,6 +257,7 @@ bool isSoloAX(MCInstrInfo const &MCII, MCInst const &MCI); /// Return whether the insn can be packaged only with an A-type insn in slot #1. bool isSoloAin1(MCInstrInfo const &MCII, MCInst const &MCI); +bool isVector(MCInstrInfo const &MCII, MCInst const &MCI); // Pad the bundle with nops to satisfy endloop requirements void padEndloop(MCInst &MCI); @@ -220,6 +269,8 @@ void replaceDuplex(MCContext &Context, MCInst &MCB, DuplexCandidate Candidate); // Marks a bundle as endloop0 void setInnerLoop(MCInst &MCI); +void setMemReorderDisabled(MCInst &MCI); +void setMemStoreReorderEnabled(MCInst &MCI); // Marks a bundle as endloop1 void setOuterLoop(MCInst &MCI); diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp index 53305d85fd8..c407e7cb166 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp @@ -40,6 +40,14 @@ using namespace llvm; #define GET_REGINFO_MC_DESC #include "HexagonGenRegisterInfo.inc" +cl::opt llvm::HexagonDisableCompound + ("mno-compound", + cl::desc("Disable looking for compound instructions for Hexagon")); + +cl::opt llvm::HexagonDisableDuplex + ("mno-pairing", + cl::desc("Disable looking for duplex instructions for Hexagon")); + MCInstrInfo *llvm::createHexagonMCInstrInfo() { MCInstrInfo *X = new MCInstrInfo(); InitHexagonMCInstrInfo(X); @@ -54,7 +62,10 @@ static MCRegisterInfo *createHexagonMCRegisterInfo(const Triple &TT) { static MCSubtargetInfo * createHexagonMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { - return createHexagonMCSubtargetInfoImpl(TT, CPU, FS); + StringRef CPUName = CPU; + if (CPU.empty()) + CPUName = "hexagonv5"; + return createHexagonMCSubtargetInfoImpl(TT, CPUName, FS); } namespace { diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h index cb626503313..6fcfd487feb 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h @@ -16,6 +16,8 @@ #include +#include "llvm/Support/CommandLine.h" + namespace llvm { struct InstrItinerary; struct InstrStage; @@ -33,7 +35,8 @@ class raw_ostream; class raw_pwrite_stream; extern Target TheHexagonTarget; - +extern cl::opt HexagonDisableCompound; +extern cl::opt HexagonDisableDuplex; extern const InstrStage HexagonStages[]; MCInstrInfo *createHexagonMCInstrInfo(); diff --git a/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h b/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h index 8b6c72ee25e..6355c3275a3 100644 --- a/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h +++ b/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.h @@ -108,6 +108,8 @@ public: SHUFFLE_ERROR_BRANCHES, ///< No free slots for branch insns. SHUFFLE_ERROR_NOSLOTS, ///< No free slots for other insns. SHUFFLE_ERROR_SLOTS, ///< Over-subscribed slots. + SHUFFLE_ERROR_ERRATA2, ///< Errata violation (v60). + SHUFFLE_ERROR_STORE_LOAD_CONFLICT, ///< store/load conflict SHUFFLE_ERROR_UNKNOWN ///< Unknown error. }; diff --git a/test/CodeGen/Hexagon/absaddr-store.ll b/test/CodeGen/Hexagon/absaddr-store.ll index dac8607d88d..f4e97d22e7d 100644 --- a/test/CodeGen/Hexagon/absaddr-store.ll +++ b/test/CodeGen/Hexagon/absaddr-store.ll @@ -1,5 +1,6 @@ ; RUN: llc -march=hexagon -hexagon-small-data-threshold=0 < %s | FileCheck %s ; Check that we generate load instructions with absolute addressing mode. +; XFAIL: * @a0 = external global i32 @a1 = external global i32 diff --git a/test/CodeGen/Hexagon/absimm.ll b/test/CodeGen/Hexagon/absimm.ll index e67af5e8fef..f3f10f2b4f2 100644 --- a/test/CodeGen/Hexagon/absimm.ll +++ b/test/CodeGen/Hexagon/absimm.ll @@ -1,6 +1,7 @@ ; RUN: llc -march=hexagon < %s | FileCheck %s ; Check that we generate absolute addressing mode instructions ; with immediate value. +; XFAIL: * define i32 @f1(i32 %i) nounwind { ; CHECK: memw(##786432){{ *}}={{ *}}r{{[0-9]+}} diff --git a/test/CodeGen/Hexagon/always-ext.ll b/test/CodeGen/Hexagon/always-ext.ll index 3bf465b6a51..761c1bd7ba1 100644 --- a/test/CodeGen/Hexagon/always-ext.ll +++ b/test/CodeGen/Hexagon/always-ext.ll @@ -1,4 +1,5 @@ ; RUN: llc -march=hexagon < %s | FileCheck %s +; XFAIL: * ; Check that we don't generate an invalid packet with too many instructions ; due to a store that has a must-extend operand. diff --git a/test/CodeGen/Hexagon/compound.ll b/test/CodeGen/Hexagon/compound.ll index f8d36b8b77d..55dc661086b 100644 --- a/test/CodeGen/Hexagon/compound.ll +++ b/test/CodeGen/Hexagon/compound.ll @@ -1,4 +1,5 @@ ; RUN: llc -march=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +; XFAIL: * ; CHECK: p0 = cmp.gt(r0,#-1); if (!p0.new) jump:nt diff --git a/test/CodeGen/Hexagon/static.ll b/test/CodeGen/Hexagon/static.ll index 760b8b55972..6adfaaf139e 100644 --- a/test/CodeGen/Hexagon/static.ll +++ b/test/CodeGen/Hexagon/static.ll @@ -1,4 +1,5 @@ ; RUN: llc -march=hexagon -mcpu=hexagonv4 -disable-dfa-sched -disable-hexagon-misched < %s | FileCheck %s +; XFAIL: * @num = external global i32 @acc = external global i32 diff --git a/test/CodeGen/Hexagon/zextloadi1.ll b/test/CodeGen/Hexagon/zextloadi1.ll index 9ce7bea9fce..c6c982750c0 100644 --- a/test/CodeGen/Hexagon/zextloadi1.ll +++ b/test/CodeGen/Hexagon/zextloadi1.ll @@ -1,4 +1,5 @@ ; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s +; XFAIL: * ; CHECK: r{{[0-9]+}} = ##i129_l+16 ; CHECK: r{{[0-9]+}} = ##i129_s+16 diff --git a/test/MC/Disassembler/Hexagon/invalid_packet.txt b/test/MC/Disassembler/Hexagon/invalid_packet.txt new file mode 100644 index 00000000000..8ce0ca90dc5 --- /dev/null +++ b/test/MC/Disassembler/Hexagon/invalid_packet.txt @@ -0,0 +1,4 @@ +# RUN: llvm-mc -triple=hexagon -disassemble < %s 2>&1 | FileCheck %s + +#CHECK: warning: invalid instruction encoding +0x00 0x40 0x20 0x6c 0x00 0xc0 0x00 0x7f \ No newline at end of file diff --git a/test/MC/Disassembler/Hexagon/j.txt b/test/MC/Disassembler/Hexagon/j.txt index 0c2cc7a4cf3..661670e2a61 100644 --- a/test/MC/Disassembler/Hexagon/j.txt +++ b/test/MC/Disassembler/Hexagon/j.txt @@ -11,149 +11,149 @@ # Compare and jump 0x00 0xc0 0x89 0x11 -# CHECK: p0 = cmp.eq(r9,#-1); if (p0.new) jump:nt +# CHECK: p0 = cmp.eq(r17,#-1); if (p0.new) jump:nt 0x00 0xc1 0x89 0x11 -# CHECK: p0 = cmp.gt(r9,#-1); if (p0.new) jump:nt +# CHECK: p0 = cmp.gt(r17,#-1); if (p0.new) jump:nt 0x00 0xc3 0x89 0x11 -# CHECK: p0 = tstbit(r9, #0); if (p0.new) jump:nt +# CHECK: p0 = tstbit(r17, #0); if (p0.new) jump:nt 0x00 0xe0 0x89 0x11 -# CHECK: p0 = cmp.eq(r9,#-1); if (p0.new) jump:t +# CHECK: p0 = cmp.eq(r17,#-1); if (p0.new) jump:t 0x00 0xe1 0x89 0x11 -# CHECK: p0 = cmp.gt(r9,#-1); if (p0.new) jump:t +# CHECK: p0 = cmp.gt(r17,#-1); if (p0.new) jump:t 0x00 0xe3 0x89 0x11 -# CHECK: p0 = tstbit(r9, #0); if (p0.new) jump:t +# CHECK: p0 = tstbit(r17, #0); if (p0.new) jump:t 0x00 0xc0 0xc9 0x11 -# CHECK: p0 = cmp.eq(r9,#-1); if (!p0.new) jump:nt +# CHECK: p0 = cmp.eq(r17,#-1); if (!p0.new) jump:nt 0x00 0xc1 0xc9 0x11 -# CHECK: p0 = cmp.gt(r9,#-1); if (!p0.new) jump:nt +# CHECK: p0 = cmp.gt(r17,#-1); if (!p0.new) jump:nt 0x00 0xc3 0xc9 0x11 -# CHECK: p0 = tstbit(r9, #0); if (!p0.new) jump:nt +# CHECK: p0 = tstbit(r17, #0); if (!p0.new) jump:nt 0x00 0xe0 0xc9 0x11 -# CHECK: p0 = cmp.eq(r9,#-1); if (!p0.new) jump:t +# CHECK: p0 = cmp.eq(r17,#-1); if (!p0.new) jump:t 0x00 0xe1 0xc9 0x11 -# CHECK: p0 = cmp.gt(r9,#-1); if (!p0.new) jump:t +# CHECK: p0 = cmp.gt(r17,#-1); if (!p0.new) jump:t 0x00 0xe3 0xc9 0x11 -# CHECK: p0 = tstbit(r9, #0); if (!p0.new) jump:t +# CHECK: p0 = tstbit(r17, #0); if (!p0.new) jump:t 0x00 0xd5 0x09 0x10 -# CHECK: p0 = cmp.eq(r9, #21); if (p0.new) jump:nt +# CHECK: p0 = cmp.eq(r17, #21); if (p0.new) jump:nt 0x00 0xf5 0x09 0x10 -# CHECK: p0 = cmp.eq(r9, #21); if (p0.new) jump:t +# CHECK: p0 = cmp.eq(r17, #21); if (p0.new) jump:t 0x00 0xd5 0x49 0x10 -# CHECK: p0 = cmp.eq(r9, #21); if (!p0.new) jump:nt +# CHECK: p0 = cmp.eq(r17, #21); if (!p0.new) jump:nt 0x00 0xf5 0x49 0x10 -# CHECK: p0 = cmp.eq(r9, #21); if (!p0.new) jump:t +# CHECK: p0 = cmp.eq(r17, #21); if (!p0.new) jump:t 0x00 0xd5 0x89 0x10 -# CHECK: p0 = cmp.gt(r9, #21); if (p0.new) jump:nt +# CHECK: p0 = cmp.gt(r17, #21); if (p0.new) jump:nt 0x00 0xf5 0x89 0x10 -# CHECK: p0 = cmp.gt(r9, #21); if (p0.new) jump:t +# CHECK: p0 = cmp.gt(r17, #21); if (p0.new) jump:t 0x00 0xd5 0xc9 0x10 -# CHECK: p0 = cmp.gt(r9, #21); if (!p0.new) jump:nt +# CHECK: p0 = cmp.gt(r17, #21); if (!p0.new) jump:nt 0x00 0xf5 0xc9 0x10 -# CHECK: p0 = cmp.gt(r9, #21); if (!p0.new) jump:t +# CHECK: p0 = cmp.gt(r17, #21); if (!p0.new) jump:t 0x00 0xd5 0x09 0x11 -# CHECK: p0 = cmp.gtu(r9, #21); if (p0.new) jump:nt +# CHECK: p0 = cmp.gtu(r17, #21); if (p0.new) jump:nt 0x00 0xf5 0x09 0x11 -# CHECK: p0 = cmp.gtu(r9, #21); if (p0.new) jump:t +# CHECK: p0 = cmp.gtu(r17, #21); if (p0.new) jump:t 0x00 0xd5 0x49 0x11 -# CHECK: p0 = cmp.gtu(r9, #21); if (!p0.new) jump:nt +# CHECK: p0 = cmp.gtu(r17, #21); if (!p0.new) jump:nt 0x00 0xf5 0x49 0x11 -# CHECK: p0 = cmp.gtu(r9, #21); if (!p0.new) jump:t +# CHECK: p0 = cmp.gtu(r17, #21); if (!p0.new) jump:t 0x00 0xc0 0x89 0x13 -# CHECK: p1 = cmp.eq(r9,#-1); if (p1.new) jump:nt +# CHECK: p1 = cmp.eq(r17,#-1); if (p1.new) jump:nt 0x00 0xc1 0x89 0x13 -# CHECK: p1 = cmp.gt(r9,#-1); if (p1.new) jump:nt +# CHECK: p1 = cmp.gt(r17,#-1); if (p1.new) jump:nt 0x00 0xc3 0x89 0x13 -# CHECK: p1 = tstbit(r9, #0); if (p1.new) jump:nt +# CHECK: p1 = tstbit(r17, #0); if (p1.new) jump:nt 0x00 0xe0 0x89 0x13 -# CHECK: p1 = cmp.eq(r9,#-1); if (p1.new) jump:t +# CHECK: p1 = cmp.eq(r17,#-1); if (p1.new) jump:t 0x00 0xe1 0x89 0x13 -# CHECK: p1 = cmp.gt(r9,#-1); if (p1.new) jump:t +# CHECK: p1 = cmp.gt(r17,#-1); if (p1.new) jump:t 0x00 0xe3 0x89 0x13 -# CHECK: p1 = tstbit(r9, #0); if (p1.new) jump:t +# CHECK: p1 = tstbit(r17, #0); if (p1.new) jump:t 0x00 0xc0 0xc9 0x13 -# CHECK: p1 = cmp.eq(r9,#-1); if (!p1.new) jump:nt +# CHECK: p1 = cmp.eq(r17,#-1); if (!p1.new) jump:nt 0x00 0xc1 0xc9 0x13 -# CHECK: p1 = cmp.gt(r9,#-1); if (!p1.new) jump:nt +# CHECK: p1 = cmp.gt(r17,#-1); if (!p1.new) jump:nt 0x00 0xc3 0xc9 0x13 -# CHECK: p1 = tstbit(r9, #0); if (!p1.new) jump:nt +# CHECK: p1 = tstbit(r17, #0); if (!p1.new) jump:nt 0x00 0xe0 0xc9 0x13 -# CHECK: p1 = cmp.eq(r9,#-1); if (!p1.new) jump:t +# CHECK: p1 = cmp.eq(r17,#-1); if (!p1.new) jump:t 0x00 0xe1 0xc9 0x13 -# CHECK: p1 = cmp.gt(r9,#-1); if (!p1.new) jump:t +# CHECK: p1 = cmp.gt(r17,#-1); if (!p1.new) jump:t 0x00 0xe3 0xc9 0x13 -# CHECK: p1 = tstbit(r9, #0); if (!p1.new) jump:t +# CHECK: p1 = tstbit(r17, #0); if (!p1.new) jump:t 0x00 0xd5 0x09 0x12 -# CHECK: p1 = cmp.eq(r9, #21); if (p1.new) jump:nt +# CHECK: p1 = cmp.eq(r17, #21); if (p1.new) jump:nt 0x00 0xf5 0x09 0x12 -# CHECK: p1 = cmp.eq(r9, #21); if (p1.new) jump:t +# CHECK: p1 = cmp.eq(r17, #21); if (p1.new) jump:t 0x00 0xd5 0x49 0x12 -# CHECK: p1 = cmp.eq(r9, #21); if (!p1.new) jump:nt +# CHECK: p1 = cmp.eq(r17, #21); if (!p1.new) jump:nt 0x00 0xf5 0x49 0x12 -# CHECK: p1 = cmp.eq(r9, #21); if (!p1.new) jump:t +# CHECK: p1 = cmp.eq(r17, #21); if (!p1.new) jump:t 0x00 0xd5 0x89 0x12 -# CHECK: p1 = cmp.gt(r9, #21); if (p1.new) jump:nt +# CHECK: p1 = cmp.gt(r17, #21); if (p1.new) jump:nt 0x00 0xf5 0x89 0x12 -# CHECK: p1 = cmp.gt(r9, #21); if (p1.new) jump:t +# CHECK: p1 = cmp.gt(r17, #21); if (p1.new) jump:t 0x00 0xd5 0xc9 0x12 -# CHECK: p1 = cmp.gt(r9, #21); if (!p1.new) jump:nt +# CHECK: p1 = cmp.gt(r17, #21); if (!p1.new) jump:nt 0x00 0xf5 0xc9 0x12 -# CHECK: p1 = cmp.gt(r9, #21); if (!p1.new) jump:t +# CHECK: p1 = cmp.gt(r17, #21); if (!p1.new) jump:t 0x00 0xd5 0x09 0x13 -# CHECK: p1 = cmp.gtu(r9, #21); if (p1.new) jump:nt +# CHECK: p1 = cmp.gtu(r17, #21); if (p1.new) jump:nt 0x00 0xf5 0x09 0x13 -# CHECK: p1 = cmp.gtu(r9, #21); if (p1.new) jump:t +# CHECK: p1 = cmp.gtu(r17, #21); if (p1.new) jump:t 0x00 0xd5 0x49 0x13 -# CHECK: p1 = cmp.gtu(r9, #21); if (!p1.new) jump:nt +# CHECK: p1 = cmp.gtu(r17, #21); if (!p1.new) jump:nt 0x00 0xf5 0x49 0x13 -# CHECK: p1 = cmp.gtu(r9, #21); if (!p1.new) jump:t +# CHECK: p1 = cmp.gtu(r17, #21); if (!p1.new) jump:t 0x00 0xcd 0x09 0x14 -# CHECK: p0 = cmp.eq(r9, r13); if (p0.new) jump:nt +# CHECK: p0 = cmp.eq(r17, r21); if (p0.new) jump:nt 0x00 0xdd 0x09 0x14 -# CHECK: p1 = cmp.eq(r9, r13); if (p1.new) jump:nt +# CHECK: p1 = cmp.eq(r17, r21); if (p1.new) jump:nt 0x00 0xed 0x09 0x14 -# CHECK: p0 = cmp.eq(r9, r13); if (p0.new) jump:t +# CHECK: p0 = cmp.eq(r17, r21); if (p0.new) jump:t 0x00 0xfd 0x09 0x14 -# CHECK: p1 = cmp.eq(r9, r13); if (p1.new) jump:t +# CHECK: p1 = cmp.eq(r17, r21); if (p1.new) jump:t 0x00 0xcd 0x49 0x14 -# CHECK: p0 = cmp.eq(r9, r13); if (!p0.new) jump:nt +# CHECK: p0 = cmp.eq(r17, r21); if (!p0.new) jump:nt 0x00 0xdd 0x49 0x14 -# CHECK: p1 = cmp.eq(r9, r13); if (!p1.new) jump:nt +# CHECK: p1 = cmp.eq(r17, r21); if (!p1.new) jump:nt 0x00 0xed 0x49 0x14 -# CHECK: p0 = cmp.eq(r9, r13); if (!p0.new) jump:t +# CHECK: p0 = cmp.eq(r17, r21); if (!p0.new) jump:t 0x00 0xfd 0x49 0x14 -# CHECK: p1 = cmp.eq(r9, r13); if (!p1.new) jump:t +# CHECK: p1 = cmp.eq(r17, r21); if (!p1.new) jump:t 0x00 0xcd 0x89 0x14 -# CHECK: p0 = cmp.gt(r9, r13); if (p0.new) jump:nt +# CHECK: p0 = cmp.gt(r17, r21); if (p0.new) jump:nt 0x00 0xdd 0x89 0x14 -# CHECK: p1 = cmp.gt(r9, r13); if (p1.new) jump:nt +# CHECK: p1 = cmp.gt(r17, r21); if (p1.new) jump:nt 0x00 0xed 0x89 0x14 -# CHECK: p0 = cmp.gt(r9, r13); if (p0.new) jump:t +# CHECK: p0 = cmp.gt(r17, r21); if (p0.new) jump:t 0x00 0xfd 0x89 0x14 -# CHECK: p1 = cmp.gt(r9, r13); if (p1.new) jump:t +# CHECK: p1 = cmp.gt(r17, r21); if (p1.new) jump:t 0x00 0xcd 0xc9 0x14 -# CHECK: p0 = cmp.gt(r9, r13); if (!p0.new) jump:nt +# CHECK: p0 = cmp.gt(r17, r21); if (!p0.new) jump:nt 0x00 0xdd 0xc9 0x14 -# CHECK: p1 = cmp.gt(r9, r13); if (!p1.new) jump:nt +# CHECK: p1 = cmp.gt(r17, r21); if (!p1.new) jump:nt 0x00 0xed 0xc9 0x14 -# CHECK: p0 = cmp.gt(r9, r13); if (!p0.new) jump:t +# CHECK: p0 = cmp.gt(r17, r21); if (!p0.new) jump:t 0x00 0xfd 0xc9 0x14 -# CHECK: p1 = cmp.gt(r9, r13); if (!p1.new) jump:t +# CHECK: p1 = cmp.gt(r17, r21); if (!p1.new) jump:t 0x00 0xcd 0x09 0x15 -# CHECK: p0 = cmp.gtu(r9, r13); if (p0.new) jump:nt +# CHECK: p0 = cmp.gtu(r17, r21); if (p0.new) jump:nt 0x00 0xdd 0x09 0x15 -# CHECK: p1 = cmp.gtu(r9, r13); if (p1.new) jump:nt +# CHECK: p1 = cmp.gtu(r17, r21); if (p1.new) jump:nt 0x00 0xed 0x09 0x15 -# CHECK: p0 = cmp.gtu(r9, r13); if (p0.new) jump:t +# CHECK: p0 = cmp.gtu(r17, r21); if (p0.new) jump:t 0x00 0xfd 0x09 0x15 -# CHECK: p1 = cmp.gtu(r9, r13); if (p1.new) jump:t +# CHECK: p1 = cmp.gtu(r17, r21); if (p1.new) jump:t 0x00 0xcd 0x49 0x15 -# CHECK: p0 = cmp.gtu(r9, r13); if (!p0.new) jump:nt +# CHECK: p0 = cmp.gtu(r17, r21); if (!p0.new) jump:nt 0x00 0xdd 0x49 0x15 -# CHECK: p1 = cmp.gtu(r9, r13); if (!p1.new) jump:nt +# CHECK: p1 = cmp.gtu(r17, r21); if (!p1.new) jump:nt 0x00 0xed 0x49 0x15 -# CHECK: p0 = cmp.gtu(r9, r13); if (!p0.new) jump:t +# CHECK: p0 = cmp.gtu(r17, r21); if (!p0.new) jump:t 0x00 0xfd 0x49 0x15 -# CHECK: p1 = cmp.gtu(r9, r13); if (!p1.new) jump:t +# CHECK: p1 = cmp.gtu(r17, r21); if (!p1.new) jump:t # Jump to address 0x22 0xc0 0x00 0x58 @@ -197,6 +197,6 @@ # Transfer and jump 0x00 0xd5 0x09 0x16 -# CHECK: r9 = #21 ; jump +# CHECK: r17 = #21 ; jump 0x00 0xc9 0x0d 0x17 -# CHECK: r9 = r13 ; jump +# CHECK: r17 = r21 ; jump diff --git a/test/MC/Disassembler/Hexagon/ld.txt b/test/MC/Disassembler/Hexagon/ld.txt index 15c23b64488..f4311570e40 100644 --- a/test/MC/Disassembler/Hexagon/ld.txt +++ b/test/MC/Disassembler/Hexagon/ld.txt @@ -1,15 +1,22 @@ # RUN: llvm-mc -triple hexagon -disassemble < %s | FileCheck %s # Hexagon Programmer's Reference Manual 11.5 LD +# XFAIL: * # Load doubleword 0x90 0xff 0xd5 0x3a # CHECK: r17:16 = memd(r21 + r31<<#3) -0x10 0xc5 0xc0 0x49 -# CHECK: r17:16 = memd(##320) +0xb0 0xc2 0xc0 0x49 +# CHECK: r17:16 = memd(#168) +0x02 0x40 0x00 0x00 0x10 0xc5 0xc0 0x49 +# CHECK: r17:16 = memd(##168) +0xd0 0xc0 0xd5 0x91 +# CHECK: r17:16 = memd(r21 + #48) 0xb0 0xe0 0xd5 0x99 # CHECK: r17:16 = memd(r21 ++ #40:circ(m1)) 0x10 0xe2 0xd5 0x99 # CHECK: r17:16 = memd(r21 ++ I:circ(m1)) +0x00 0x40 0x00 0x00 0x70 0xd7 0xd5 0x9b +# CHECK: r17:16 = memd(r21 = ##31) 0xb0 0xc0 0xd5 0x9b # CHECK: r17:16 = memd(r21++#40) 0x10 0xe0 0xd5 0x9d @@ -53,6 +60,8 @@ 0x91 0xff 0x15 0x3a # CHECK: r17 = memb(r21 + r31<<#3) 0xb1 0xc2 0x00 0x49 +# CHECK: r17 = memb(#21) +0x00 0x40 0x00 0x00 0xb1 0xc2 0x00 0x49 # CHECK: r17 = memb(##21) 0xf1 0xc3 0x15 0x91 # CHECK: r17 = memb(r21 + #31) @@ -60,6 +69,8 @@ # CHECK: r17 = memb(r21 ++ #5:circ(m1)) 0x11 0xe2 0x15 0x99 # CHECK: r17 = memb(r21 ++ I:circ(m1)) +0x00 0x40 0x00 0x00 0x71 0xd7 0x15 0x9b +# CHECK: r17 = memb(r21 = ##31) 0xb1 0xc0 0x15 0x9b # CHECK: r17 = memb(r21++#5) 0x11 0xe0 0x15 0x9d @@ -99,17 +110,37 @@ # CHECK: p3 = r5 # CHECK-NEXT: if (!p3.new) r17 = memb(r21++#5) +# Load byte into shifted vector +0xf0 0xc3 0x95 0x90 +# CHECK: r17:16 = memb_fifo(r21 + #31) +0xb0 0xe0 0x95 0x98 +# CHECK: r17:16 = memb_fifo(r21 ++ #5:circ(m1)) +0x10 0xe2 0x95 0x98 +# CHECK: r17:16 = memb_fifo(r21 ++ I:circ(m1)) + +# Load half into shifted vector +0xf0 0xc3 0x55 0x90 +# CHECK: r17:16 = memh_fifo(r21 + #62) +0xb0 0xe0 0x55 0x98 +# CHECK: r17:16 = memh_fifo(r21 ++ #10:circ(m1)) +0x10 0xe2 0x55 0x98 +# CHECK: r17:16 = memh_fifo(r21 ++ I:circ(m1)) + # Load halfword 0x91 0xff 0x55 0x3a # CHECK: r17 = memh(r21 + r31<<#3) -0x51 0xc5 0x40 0x49 -# CHECK: r17 = memh(##84) +0xb1 0xc2 0x40 0x49 +# CHECK: r17 = memh(#42) +0x00 0x40 0x00 0x00 0x51 0xc5 0x40 0x49 +# CHECK: r17 = memh(##42) 0xf1 0xc3 0x55 0x91 # CHECK: r17 = memh(r21 + #62) 0xb1 0xe0 0x55 0x99 # CHECK: r17 = memh(r21 ++ #10:circ(m1)) 0x11 0xe2 0x55 0x99 # CHECK: r17 = memh(r21 ++ I:circ(m1)) +0x00 0x40 0x00 0x00 0x71 0xd7 0x55 0x9b +# CHECK: r17 = memh(r21 = ##31) 0xb1 0xc0 0x55 0x9b # CHECK: r17 = memh(r21++#10) 0x11 0xe0 0x55 0x9d @@ -138,11 +169,23 @@ 0x03 0x40 0x45 0x85 0xb1 0xfe 0x55 0x9b # CHECK: p3 = r5 # CHECK-NEXT: if (!p3.new) r17 = memh(r21++#10) +0xf1 0xdb 0x55 0x41 +# CHECK: if (p3) r17 = memh(r21 + #62) +0xf1 0xdb 0x55 0x45 +# CHECK: if (!p3) r17 = memh(r21 + #62) +0x03 0x40 0x45 0x85 0xf1 0xdb 0x55 0x43 +# CHECK: p3 = r5 +# CHECK-NEXT: if (p3.new) r17 = memh(r21 + #62) +0x03 0x40 0x45 0x85 0xf1 0xdb 0x55 0x47 +# CHECK: p3 = r5 +# CHECK-NEXT: if (!p3.new) r17 = memh(r21 + #62) # Load unsigned byte 0x91 0xff 0x35 0x3a # CHECK: r17 = memub(r21 + r31<<#3) 0xb1 0xc2 0x20 0x49 +# CHECK: r17 = memub(#21) +0x00 0x40 0x00 0x00 0xb1 0xc2 0x20 0x49 # CHECK: r17 = memub(##21) 0xf1 0xc3 0x35 0x91 # CHECK: r17 = memub(r21 + #31) @@ -150,6 +193,8 @@ # CHECK: r17 = memub(r21 ++ #5:circ(m1)) 0x11 0xe2 0x35 0x99 # CHECK: r17 = memub(r21 ++ I:circ(m1)) +0x00 0x40 0x00 0x00 0x71 0xd7 0x35 0x9b +# CHECK: r17 = memub(r21 = ##31) 0xb1 0xc0 0x35 0x9b # CHECK: r17 = memub(r21++#5) 0x11 0xe0 0x35 0x9d @@ -192,14 +237,18 @@ # Load unsigned halfword 0x91 0xff 0x75 0x3a # CHECK: r17 = memuh(r21 + r31<<#3) -0x51 0xc5 0x60 0x49 -# CHECK: r17 = memuh(##84) +0xb1 0xc2 0x60 0x49 +# CHECK: r17 = memuh(#42) +0x00 0x40 0x00 0x00 0x51 0xc5 0x60 0x49 +# CHECK: r17 = memuh(##42) 0xb1 0xc2 0x75 0x91 # CHECK: r17 = memuh(r21 + #42) 0xb1 0xe0 0x75 0x99 # CHECK: r17 = memuh(r21 ++ #10:circ(m1)) 0x11 0xe2 0x75 0x99 # CHECK: r17 = memuh(r21 ++ I:circ(m1)) +0x00 0x40 0x00 0x00 0x71 0xd7 0x75 0x9b +# CHECK: r17 = memuh(r21 = ##31) 0xb1 0xc0 0x75 0x9b # CHECK: r17 = memuh(r21++#10) 0x11 0xe0 0x75 0x9d @@ -242,14 +291,18 @@ # Load word 0x91 0xff 0x95 0x3a # CHECK: r17 = memw(r21 + r31<<#3) -0x91 0xc2 0x80 0x49 -# CHECK: r17 = memw(##80) +0xb1 0xc2 0x80 0x49 +# CHECK: r17 = memw(#84) +0x01 0x40 0x00 0x00 0x91 0xc2 0x80 0x49 +# CHECK: r17 = memw(##84) 0xb1 0xc2 0x95 0x91 # CHECK: r17 = memw(r21 + #84) 0xb1 0xe0 0x95 0x99 # CHECK: r17 = memw(r21 ++ #20:circ(m1)) 0x11 0xe2 0x95 0x99 # CHECK: r17 = memw(r21 ++ I:circ(m1)) +0x00 0x40 0x00 0x00 0x71 0xd7 0x95 0x9b +# CHECK: r17 = memw(r21 = ##31) 0xb1 0xc0 0x95 0x9b # CHECK: r17 = memw(r21++#20) 0x11 0xe0 0x95 0x9d @@ -338,14 +391,36 @@ # CHECK: r17:16 = memubh(r21 ++ #20:circ(m1)) 0x10 0xe2 0xb5 0x98 # CHECK: r17:16 = memubh(r21 ++ I:circ(m1)) +0x00 0x40 0x00 0x00 0x71 0xd7 0x35 0x9a +# CHECK: r17 = membh(r21 = ##31) 0xb1 0xc0 0x35 0x9a # CHECK: r17 = membh(r21++#10) +0x00 0x40 0x00 0x00 0x71 0xd7 0x75 0x9a +# CHECK: r17 = memubh(r21 = ##31) 0xb1 0xc0 0x75 0x9a # CHECK: r17 = memubh(r21++#10) +0x00 0x40 0x00 0x00 0x70 0xd7 0xb5 0x9a +# CHECK: r17:16 = memubh(r21 = ##31) 0xb0 0xc0 0xb5 0x9a # CHECK: r17:16 = memubh(r21++#20) +0x00 0x40 0x00 0x00 0x70 0xd7 0xf5 0x9a +# CHECK: r17:16 = membh(r21 = ##31) 0xb0 0xc0 0xf5 0x9a # CHECK: r17:16 = membh(r21++#20) +0x00 0x40 0x00 0x00 0xf1 0xf7 0x35 0x9c +# CHECK: r17 = membh(r21<<#3 + ##31) +0x11 0xe0 0x35 0x9c +# CHECK: r17 = membh(r21++m1) +0x00 0x40 0x00 0x00 0xf1 0xf7 0x75 0x9c +# CHECK: r17 = memubh(r21<<#3 + ##31) +0x11 0xe0 0x75 0x9c +# CHECK: r17 = memubh(r21++m1) +0x00 0x40 0x00 0x00 0xf0 0xf7 0xf5 0x9c +# CHECK: r17:16 = membh(r21<<#3 + ##31) +0x10 0xe0 0xf5 0x9c +# CHECK: r17:16 = membh(r21++m1) +0x00 0x40 0x00 0x00 0xf0 0xf7 0xb5 0x9c +# CHECK: r17:16 = memubh(r21<<#3 + ##31) 0x11 0xe0 0x35 0x9c # CHECK: r17 = membh(r21++m1) 0x11 0xe0 0x75 0x9c diff --git a/test/MC/Disassembler/Hexagon/lit.local.cfg b/test/MC/Disassembler/Hexagon/lit.local.cfg index 6500d4dd7d5..ba72ff632d4 100644 --- a/test/MC/Disassembler/Hexagon/lit.local.cfg +++ b/test/MC/Disassembler/Hexagon/lit.local.cfg @@ -1,3 +1,3 @@ -if not 'Hexagon' in config.root.targets: - config.unsupported = True - +if not 'Hexagon' in config.root.targets: + config.unsupported = True + diff --git a/test/MC/Disassembler/Hexagon/nv_j.txt b/test/MC/Disassembler/Hexagon/nv_j.txt index a6773c3f3c5..2135b5a039f 100644 --- a/test/MC/Disassembler/Hexagon/nv_j.txt +++ b/test/MC/Disassembler/Hexagon/nv_j.txt @@ -4,133 +4,133 @@ # Jump to address conditioned on new register value 0x11 0x40 0x71 0x70 0x92 0xd5 0x02 0x20 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.eq(r2.new, r21)) jump:nt +# CHECK-NEXT: if (cmp.eq(r17.new, r21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x02 0x20 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.eq(r2.new, r21)) jump:t +# CHECK-NEXT: if (cmp.eq(r17.new, r21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x42 0x20 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.eq(r2.new, r21)) jump:nt +# CHECK-NEXT: if (!cmp.eq(r17.new, r21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x42 0x20 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.eq(r2.new, r21)) jump:t +# CHECK-NEXT: if (!cmp.eq(r17.new, r21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x82 0x20 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gt(r2.new, r21)) jump:nt +# CHECK-NEXT: if (cmp.gt(r17.new, r21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x82 0x20 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gt(r2.new, r21)) jump:t +# CHECK-NEXT: if (cmp.gt(r17.new, r21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0xc2 0x20 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gt(r2.new, r21)) jump:nt +# CHECK-NEXT: if (!cmp.gt(r17.new, r21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0xc2 0x20 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gt(r2.new, r21)) jump:t +# CHECK-NEXT: if (!cmp.gt(r17.new, r21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x02 0x21 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gtu(r2.new, r21)) jump:nt +# CHECK-NEXT: if (cmp.gtu(r17.new, r21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x02 0x21 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gtu(r2.new, r21)) jump:t +# CHECK-NEXT: if (cmp.gtu(r17.new, r21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x42 0x21 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gtu(r2.new, r21)) jump:nt +# CHECK-NEXT: if (!cmp.gtu(r17.new, r21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x42 0x21 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gtu(r2.new, r21)) jump:t +# CHECK-NEXT: if (!cmp.gtu(r17.new, r21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x82 0x21 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gt(r21, r2.new)) jump:nt +# CHECK-NEXT: if (cmp.gt(r21, r17.new)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x82 0x21 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gt(r21, r2.new)) jump:t +# CHECK-NEXT: if (cmp.gt(r21, r17.new)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0xc2 0x21 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gt(r21, r2.new)) jump:nt +# CHECK-NEXT: if (!cmp.gt(r21, r17.new)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0xc2 0x21 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gt(r21, r2.new)) jump:t +# CHECK-NEXT: if (!cmp.gt(r21, r17.new)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x02 0x22 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gtu(r21, r2.new)) jump:nt +# CHECK-NEXT: if (cmp.gtu(r21, r17.new)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x02 0x22 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gtu(r21, r2.new)) jump:t +# CHECK-NEXT: if (cmp.gtu(r21, r17.new)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x42 0x22 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gtu(r21, r2.new)) jump:nt +# CHECK-NEXT: if (!cmp.gtu(r21, r17.new)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x42 0x22 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gtu(r21, r2.new)) jump:t +# CHECK-NEXT: if (!cmp.gtu(r21, r17.new)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x02 0x24 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.eq(r2.new, #21)) jump:nt +# CHECK-NEXT: if (cmp.eq(r17.new, #21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x02 0x24 # CHECK: r17 = r17 -# CHECK-NETX: if (cmp.eq(r2.new, #21)) jump:t +# CHECK-NETX: if (cmp.eq(r17.new, #21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x42 0x24 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.eq(r2.new, #21)) jump:nt +# CHECK-NEXT: if (!cmp.eq(r17.new, #21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x42 0x24 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.eq(r2.new, #21)) jump:t +# CHECK-NEXT: if (!cmp.eq(r17.new, #21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x82 0x24 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gt(r2.new, #21)) jump:nt +# CHECK-NEXT: if (cmp.gt(r17.new, #21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x82 0x24 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gt(r2.new, #21)) jump:t +# CHECK-NEXT: if (cmp.gt(r17.new, #21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0xc2 0x24 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gt(r2.new, #21)) jump:nt +# CHECK-NEXT: if (!cmp.gt(r17.new, #21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0xc2 0x24 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gt(r2.new, #21)) jump:t +# CHECK-NEXT: if (!cmp.gt(r17.new, #21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x02 0x25 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gtu(r2.new, #21)) jump:nt +# CHECK-NEXT: if (cmp.gtu(r17.new, #21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x02 0x25 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gtu(r2.new, #21)) jump:t +# CHECK-NEXT: if (cmp.gtu(r17.new, #21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xd5 0x42 0x25 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gtu(r2.new, #21)) jump:nt +# CHECK-NEXT: if (!cmp.gtu(r17.new, #21)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xf5 0x42 0x25 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gtu(r2.new, #21)) jump:t +# CHECK-NEXT: if (!cmp.gtu(r17.new, #21)) jump:t 0x11 0x40 0x71 0x70 0x92 0xc0 0x82 0x25 # CHECK: r17 = r17 -# CHECK-NEXT: if (tstbit(r2.new, #0)) jump:nt +# CHECK-NEXT: if (tstbit(r17.new, #0)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xe0 0x82 0x25 # CHECK: r17 = r17 -# CHECK-NEXT: if (tstbit(r2.new, #0)) jump:t +# CHECK-NEXT: if (tstbit(r17.new, #0)) jump:t 0x11 0x40 0x71 0x70 0x92 0xc0 0xc2 0x25 # CHECK: r17 = r17 -# CHECK-NEXT: if (!tstbit(r2.new, #0)) jump:nt +# CHECK-NEXT: if (!tstbit(r17.new, #0)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xe0 0xc2 0x25 # CHECK: r17 = r17 -# CHECK-NEXT: if (!tstbit(r2.new, #0)) jump:t +# CHECK-NEXT: if (!tstbit(r17.new, #0)) jump:t 0x11 0x40 0x71 0x70 0x92 0xc0 0x02 0x26 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.eq(r2.new, #-1)) jump:nt +# CHECK-NEXT: if (cmp.eq(r17.new, #-1)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xe0 0x02 0x26 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.eq(r2.new, #-1)) jump:t +# CHECK-NEXT: if (cmp.eq(r17.new, #-1)) jump:t 0x11 0x40 0x71 0x70 0x92 0xc0 0x42 0x26 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.eq(r2.new, #-1)) jump:nt +# CHECK-NEXT: if (!cmp.eq(r17.new, #-1)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xe0 0x42 0x26 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.eq(r2.new, #-1)) jump:t +# CHECK-NEXT: if (!cmp.eq(r17.new, #-1)) jump:t 0x11 0x40 0x71 0x70 0x92 0xc0 0x82 0x26 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gt(r2.new, #-1)) jump:nt +# CHECK-NEXT: if (cmp.gt(r17.new, #-1)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xe0 0x82 0x26 # CHECK: r17 = r17 -# CHECK-NEXT: if (cmp.gt(r2.new, #-1)) jump:t +# CHECK-NEXT: if (cmp.gt(r17.new, #-1)) jump:t 0x11 0x40 0x71 0x70 0x92 0xc0 0xc2 0x26 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gt(r2.new, #-1)) jump:nt +# CHECK-NEXT: if (!cmp.gt(r17.new, #-1)) jump:nt 0x11 0x40 0x71 0x70 0x92 0xe0 0xc2 0x26 # CHECK: r17 = r17 -# CHECK-NEXT: if (!cmp.gt(r2.new, #-1)) jump:t +# CHECK-NEXT: if (!cmp.gt(r17.new, #-1)) jump:t diff --git a/test/MC/Disassembler/Hexagon/nv_st.txt b/test/MC/Disassembler/Hexagon/nv_st.txt index ef49455b80b..3a767f33b36 100644 --- a/test/MC/Disassembler/Hexagon/nv_st.txt +++ b/test/MC/Disassembler/Hexagon/nv_st.txt @@ -4,200 +4,209 @@ # Store new-value byte 0x1f 0x40 0x7f 0x70 0x82 0xf5 0xb1 0x3b # CHECK: r31 = r31 -# CHECK-NEXT: memb(r17 + r21<<#3) = r2.new +# CHECK-NEXT: memb(r17 + r21<<#3) = r31.new +0x1f 0x40 0x7f 0x70 0x11 0xc2 0xa0 0x48 +# CHECK: r31 = r31 +# CHECK-NEXT: memb(#17) = r31.new 0x1f 0x40 0x7f 0x70 0x15 0xc2 0xb1 0xa1 # CHECK: r31 = r31 -# CHECK-NEXT: memb(r17+#21) = r2.new +# CHECK-NEXT: memb(r17+#21) = r31.new 0x1f 0x40 0x7f 0x70 0x02 0xe2 0xb1 0xa9 # CHECK: r31 = r31 -# CHECK-NEXT: memb(r17 ++ I:circ(m1)) = r2.new +# CHECK-NEXT: memb(r17 ++ I:circ(m1)) = r31.new 0x1f 0x40 0x7f 0x70 0x28 0xe2 0xb1 0xa9 # CHECK: r31 = r31 -# CHECK-NEXT: memb(r17 ++ #5:circ(m1)) = r2.new +# CHECK-NEXT: memb(r17 ++ #5:circ(m1)) = r31.new 0x1f 0x40 0x7f 0x70 0x28 0xc2 0xb1 0xab # CHECK: r31 = r31 -# CHECK-NEXT: memb(r17++#5) = r2.new +# CHECK-NEXT: memb(r17++#5) = r31.new 0x1f 0x40 0x7f 0x70 0x00 0xe2 0xb1 0xad # CHECK: r31 = r31 -# CHECK-NEXT: memb(r17++m1) = r2.new +# CHECK-NEXT: memb(r17++m1) = r31.new 0x1f 0x40 0x7f 0x70 0x00 0xe2 0xb1 0xaf # CHECK: r31 = r31 -# CHECK-NEXT: memb(r17 ++ m1:brev) = r2.new +# CHECK-NEXT: memb(r17 ++ m1:brev) = r31.new # Store new-value byte conditionally 0x1f 0x40 0x7f 0x70 0xe2 0xf5 0xb1 0x34 # CHECK: r31 = r31 -# CHECK-NEXT: if (p3) memb(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (p3) memb(r17+r21<<#3) = r31.new 0x1f 0x40 0x7f 0x70 0xe2 0xf5 0xb1 0x35 # CHECK: r31 = r31 -# CHECK-NEXT: if (!p3) memb(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (!p3) memb(r17+r21<<#3) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xe2 0xf5 0xb1 0x36 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (p3.new) memb(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (p3.new) memb(r17+r21<<#3) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xe2 0xf5 0xb1 0x37 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (!p3.new) memb(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (!p3.new) memb(r17+r21<<#3) = r31.new 0x1f 0x40 0x7f 0x70 0xab 0xc2 0xb1 0x40 # CHECK: r31 = r31 -# CHECK-NEXT: if (p3) memb(r17+#21) = r2.new +# CHECK-NEXT: if (p3) memb(r17+#21) = r31.new 0x1f 0x40 0x7f 0x70 0xab 0xc2 0xb1 0x44 # CHECK: r31 = r31 -# CHECK-NEXT: if (!p3) memb(r17+#21) = r2.new +# CHECK-NEXT: if (!p3) memb(r17+#21) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xab 0xc2 0xb1 0x42 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (p3.new) memb(r17+#21) = r2.new +# CHECK-NEXT: if (p3.new) memb(r17+#21) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xab 0xc2 0xb1 0x46 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (!p3.new) memb(r17+#21) = r2.new +# CHECK-NEXT: if (!p3.new) memb(r17+#21) = r31.new 0x1f 0x40 0x7f 0x70 0x2b 0xe2 0xb1 0xab # CHECK: r31 = r31 -# CHECK-NEXT: if (p3) memb(r17++#5) = r2.new +# CHECK-NEXT: if (p3) memb(r17++#5) = r31.new 0x1f 0x40 0x7f 0x70 0x2f 0xe2 0xb1 0xab # CHECK: r31 = r31 -# CHECK-NEXT: if (!p3) memb(r17++#5) = r2.new +# CHECK-NEXT: if (!p3) memb(r17++#5) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xab 0xe2 0xb1 0xab # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (p3.new) memb(r17++#5) = r2.new +# CHECK-NEXT: if (p3.new) memb(r17++#5) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xaf 0xe2 0xb1 0xab # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (!p3.new) memb(r17++#5) = r2.new +# CHECK-NEXT: if (!p3.new) memb(r17++#5) = r31.new # Store new-value halfword 0x1f 0x40 0x7f 0x70 0x8a 0xf5 0xb1 0x3b # CHECK: r31 = r31 -# CHECK-NEXT: memh(r17 + r21<<#3) = r2.new +# CHECK-NEXT: memh(r17 + r21<<#3) = r31.new +0x1f 0x40 0x7f 0x70 0x15 0xca 0xa0 0x48 +# CHECK: r31 = r31 +# CHECK-NEXT: memh(#42) = r31.new 0x1f 0x40 0x7f 0x70 0x15 0xca 0xb1 0xa1 # CHECK: r31 = r31 -# CHECK-NEXT: memh(r17+#42) = r2.new +# CHECK-NEXT: memh(r17+#42) = r31.new 0x1f 0x40 0x7f 0x70 0x02 0xea 0xb1 0xa9 # CHECK: r31 = r31 -# CHECK-NEXT: memh(r17 ++ I:circ(m1)) = r2.new +# CHECK-NEXT: memh(r17 ++ I:circ(m1)) = r31.new 0x1f 0x40 0x7f 0x70 0x28 0xea 0xb1 0xa9 # CHECK: r31 = r31 -# CHECK-NEXT: memh(r17 ++ #10:circ(m1)) = r2.new +# CHECK-NEXT: memh(r17 ++ #10:circ(m1)) = r31.new 0x1f 0x40 0x7f 0x70 0x28 0xca 0xb1 0xab # CHECK: r31 = r31 -# CHECK-NEXT: memh(r17++#10) = r2.new +# CHECK-NEXT: memh(r17++#10) = r31.new 0x1f 0x40 0x7f 0x70 0x00 0xea 0xb1 0xad # CHECK: r31 = r31 -# CHECK-NEXT: memh(r17++m1) = r2.new +# CHECK-NEXT: memh(r17++m1) = r31.new 0x1f 0x40 0x7f 0x70 0x00 0xea 0xb1 0xaf # CHECK: r31 = r31 -# CHECK-NEXT: memh(r17 ++ m1:brev) = r2.new +# CHECK-NEXT: memh(r17 ++ m1:brev) = r31.new # Store new-value halfword conditionally 0x1f 0x40 0x7f 0x70 0xea 0xf5 0xb1 0x34 # CHECK: r31 = r31 -# CHECK-NEXT: if (p3) memh(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (p3) memh(r17+r21<<#3) = r31.new 0x1f 0x40 0x7f 0x70 0xea 0xf5 0xb1 0x35 # CHECK: r31 = r31 -# CHECK-NEXT: if (!p3) memh(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (!p3) memh(r17+r21<<#3) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xea 0xf5 0xb1 0x36 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (p3.new) memh(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (p3.new) memh(r17+r21<<#3) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xea 0xf5 0xb1 0x37 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (!p3.new) memh(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (!p3.new) memh(r17+r21<<#3) = r31.new 0x1f 0x40 0x7f 0x70 0xab 0xca 0xb1 0x40 # CHECK: r31 = r31 -# CHECK-NEXT: if (p3) memh(r17+#42) = r2.new +# CHECK-NEXT: if (p3) memh(r17+#42) = r31.new 0x1f 0x40 0x7f 0x70 0xab 0xca 0xb1 0x44 # CHECK: r31 = r31 -# CHECK-NEXT: if (!p3) memh(r17+#42) = r2.new +# CHECK-NEXT: if (!p3) memh(r17+#42) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xab 0xca 0xb1 0x42 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (p3.new) memh(r17+#42) = r2.new +# CHECK-NEXT: if (p3.new) memh(r17+#42) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xab 0xca 0xb1 0x46 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (!p3.new) memh(r17+#42) = r2.new +# CHECK-NEXT: if (!p3.new) memh(r17+#42) = r31.new 0x1f 0x40 0x7f 0x70 0x2b 0xea 0xb1 0xab # CHECK: r31 = r31 -# CHECK-NEXT: if (p3) memh(r17++#10) = r2.new +# CHECK-NEXT: if (p3) memh(r17++#10) = r31.new 0x1f 0x40 0x7f 0x70 0x2f 0xea 0xb1 0xab # CHECK: r31 = r31 -# CHECK-NEXT: if (!p3) memh(r17++#10) = r2.new +# CHECK-NEXT: if (!p3) memh(r17++#10) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xab 0xea 0xb1 0xab # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (p3.new) memh(r17++#10) = r2.new +# CHECK-NEXT: if (p3.new) memh(r17++#10) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xaf 0xea 0xb1 0xab # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (!p3.new) memh(r17++#10) = r2.new +# CHECK-NEXT: if (!p3.new) memh(r17++#10) = r31.new # Store new-value word 0x1f 0x40 0x7f 0x70 0x92 0xf5 0xb1 0x3b # CHECK: r31 = r31 -# CHECK-NEXT: memw(r17 + r21<<#3) = r2.new -0x1f 0x40 0x7f 0x70 0x15 0xd2 0xb1 0xa1 +# CHECK-NEXT: memw(r17 + r21<<#3) = r31.new +0x1f 0x40 0x7f 0x70 0x15 0xd2 0xa0 0x48 # CHECK: r31 = r31 -# CHECK-NEXT: memw(r17+#84) = r2.new -0x1f 0x40 0x7f 0x70 0x28 0xf2 0xb1 0xa9 +# CHECK-NEXT: memw(#84) = r31.new +0x1f 0x40 0x7f 0x70 0x15 0xd2 0xb1 0xa1 # CHECK: r31 = r31 -# CHECK-NEXT: memw(r17 ++ #20:circ(m1)) = r2.new +# CHECK-NEXT: memw(r17+#84) = r31.new 0x1f 0x40 0x7f 0x70 0x02 0xf2 0xb1 0xa9 # CHECK: r31 = r31 -# CHECK-NEXT: memw(r17 ++ I:circ(m1)) = r2.new +# CHECK-NEXT: memw(r17 ++ I:circ(m1)) = r31.new +0x1f 0x40 0x7f 0x70 0x28 0xf2 0xb1 0xa9 +# CHECK: r31 = r31 +# CHECK-NEXT: memw(r17 ++ #20:circ(m1)) = r31.new 0x1f 0x40 0x7f 0x70 0x28 0xd2 0xb1 0xab # CHECK: r31 = r31 -# CHECK-NEXT: memw(r17++#20) = r2.new +# CHECK-NEXT: memw(r17++#20) = r31.new 0x1f 0x40 0x7f 0x70 0x00 0xf2 0xb1 0xad # CHECK: r31 = r31 -# CHECK-NEXT: memw(r17++m1) = r2.new +# CHECK-NEXT: memw(r17++m1) = r31.new 0x1f 0x40 0x7f 0x70 0x00 0xf2 0xb1 0xaf # CHECK: r31 = r31 -# CHECK-NEXT: memw(r17 ++ m1:brev) = r2.new +# CHECK-NEXT: memw(r17 ++ m1:brev) = r31.new # Store new-value word conditionally 0x1f 0x40 0x7f 0x70 0xf2 0xf5 0xb1 0x34 # CHECK: r31 = r31 -# CHECK-NEXT: if (p3) memw(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (p3) memw(r17+r21<<#3) = r31.new 0x1f 0x40 0x7f 0x70 0xf2 0xf5 0xb1 0x35 # CHECK: r31 = r31 -# CHECK-NEXT: if (!p3) memw(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (!p3) memw(r17+r21<<#3) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xf2 0xf5 0xb1 0x36 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (p3.new) memw(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (p3.new) memw(r17+r21<<#3) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xf2 0xf5 0xb1 0x37 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (!p3.new) memw(r17+r21<<#3) = r2.new +# CHECK-NEXT: if (!p3.new) memw(r17+r21<<#3) = r31.new 0x1f 0x40 0x7f 0x70 0xab 0xd2 0xb1 0x40 # CHECK: r31 = r31 -# CHECK-NEXT: if (p3) memw(r17+#84) = r2.new +# CHECK-NEXT: if (p3) memw(r17+#84) = r31.new 0x1f 0x40 0x7f 0x70 0xab 0xd2 0xb1 0x44 # CHECK: r31 = r31 -# CHECK-NEXT: if (!p3) memw(r17+#84) = r2.new +# CHECK-NEXT: if (!p3) memw(r17+#84) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xab 0xd2 0xb1 0x42 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (p3.new) memw(r17+#84) = r2.new +# CHECK-NEXT: if (p3.new) memw(r17+#84) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xab 0xd2 0xb1 0x46 # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (!p3.new) memw(r17+#84) = r2.new +# CHECK-NEXT: if (!p3.new) memw(r17+#84) = r31.new 0x1f 0x40 0x7f 0x70 0x2b 0xf2 0xb1 0xab # CHECK: r31 = r31 -# CHECK-NEXT: if (p3) memw(r17++#20) = r2.new +# CHECK-NEXT: if (p3) memw(r17++#20) = r31.new 0x1f 0x40 0x7f 0x70 0x2f 0xf2 0xb1 0xab # CHECK: r31 = r31 -# CHECK-NEXT: if (!p3) memw(r17++#20) = r2.new +# CHECK-NEXT: if (!p3) memw(r17++#20) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xab 0xf2 0xb1 0xab # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (p3.new) memw(r17++#20) = r2.new +# CHECK-NEXT: if (p3.new) memw(r17++#20) = r31.new 0x03 0x40 0x45 0x85 0x1f 0x40 0x7f 0x70 0xaf 0xf2 0xb1 0xab # CHECK: p3 = r5 # CHECK-NEXT: r31 = r31 -# CHECK-NEXT: if (!p3.new) memw(r17++#20) = r2.new +# CHECK-NEXT: if (!p3.new) memw(r17++#20) = r31.new diff --git a/test/MC/Disassembler/Hexagon/st.txt b/test/MC/Disassembler/Hexagon/st.txt index 3b809d3465a..4da3b54be8b 100644 --- a/test/MC/Disassembler/Hexagon/st.txt +++ b/test/MC/Disassembler/Hexagon/st.txt @@ -1,11 +1,14 @@ # RUN: llvm-mc -triple=hexagon -disassemble < %s | FileCheck %s # Hexagon Programmer's Reference Manual 11.8 ST +# XFAIL: * # Store doubleword 0x9e 0xf5 0xd1 0x3b # CHECK: memd(r17 + r21<<#3) = r31:30 0x28 0xd4 0xc0 0x48 -# CHECK: memd(##320) = r21:20 +# CHECK: memd(#320) = r21:20 +0x02 0x40 0x00 0x00 0x28 0xd4 0xc0 0x48 +# CHECK: memd(##168) = r21:20 0x15 0xd4 0xd1 0xa1 # CHECK: memd(r17+#168) = r21:20 0x02 0xf4 0xd1 0xa9 @@ -14,6 +17,8 @@ # CHECK: memd(r17 ++ #40:circ(m1)) = r21:20 0x28 0xd4 0xd1 0xab # CHECK: memd(r17++#40) = r21:20 +0x00 0x40 0x00 0x00 0xd5 0xfe 0xd1 0xad +# CHECK: memd(r17<<#3 + ##21) = r31:30 0x00 0xf4 0xd1 0xad # CHECK: memd(r17++m1) = r21:20 0x00 0xf4 0xd1 0xaf @@ -50,6 +55,16 @@ 0x03 0x40 0x45 0x85 0xaf 0xf4 0xd1 0xab # CHECK: p3 = r5 # CHECK-NEXT: if (!p3.new) memd(r17++#40) = r21:20 +0x02 0x40 0x00 0x00 0xc3 0xd4 0xc2 0xaf +# CHECK: if (p3) memd(##168) = r21:20 +0x02 0x40 0x00 0x00 0xc7 0xd4 0xc2 0xaf +# CHECK: if (!p3) memd(##168) = r21:20 +0x03 0x40 0x45 0x85 0x02 0x40 0x00 0x00 0xc3 0xf4 0xc2 0xaf +# CHECK: p3 = r5 +# CHECK-NEXT: if (p3.new) memd(##168) = r21:20 +0x03 0x40 0x45 0x85 0x02 0x40 0x00 0x00 0xc7 0xf4 0xc2 0xaf +# CHECK: p3 = r5 +# CHECK-NEXT: if (!p3.new) memd(##168) = r21:20 # Store byte 0x9f 0xf5 0x11 0x3b @@ -57,6 +72,8 @@ 0x9f 0xca 0x11 0x3c # CHECK: memb(r17+#21)=#31 0x15 0xd5 0x00 0x48 +# CHECK: memb(#21) = r21 +0x00 0x40 0x00 0x00 0x15 0xd5 0x00 0x48 # CHECK: memb(##21) = r21 0x15 0xd5 0x11 0xa1 # CHECK: memb(r17+#21) = r21 @@ -66,6 +83,8 @@ # CHECK: memb(r17 ++ #5:circ(m1)) = r21 0x28 0xd5 0x11 0xab # CHECK: memb(r17++#5) = r21 +0x00 0x40 0x00 0x00 0xd5 0xff 0x11 0xad +# CHECK: memb(r17<<#3 + ##21) = r31 0x00 0xf5 0x11 0xad # CHECK: memb(r17++m1) = r21 0x00 0xf5 0x11 0xaf @@ -112,6 +131,16 @@ 0x03 0x40 0x45 0x85 0xaf 0xf5 0x11 0xab # CHECK: p3 = r5 # CHECK-NEXT: if (!p3.new) memb(r17++#5) = r21 +0x00 0x40 0x00 0x00 0xab 0xd5 0x01 0xaf +# CHECK: if (p3) memb(##21) = r21 +0x00 0x40 0x00 0x00 0xaf 0xd5 0x01 0xaf +# CHECK: if (!p3) memb(##21) = r21 +0x03 0x40 0x45 0x85 0x00 0x40 0x00 0x00 0xab 0xf5 0x01 0xaf +# CHECK: p3 = r5 +# CHECK-NEXT: if (p3.new) memb(##21) = r21 +0x03 0x40 0x45 0x85 0x00 0x40 0x00 0x00 0xaf 0xf5 0x01 0xaf +# CHECK: p3 = r5 +# CHECK-NEXT: if (!p3.new) memb(##21) = r21 # Store halfword 0x9f 0xf5 0x51 0x3b @@ -120,10 +149,14 @@ # CHECK: memh(r17 + r21<<#3) = r31.h 0x95 0xcf 0x31 0x3c # CHECK: memh(r17+#62)=#21 +0x00 0x40 0x00 0x00 0x2a 0xd5 0x40 0x48 +# CHECK: memh(##42) = r21 +0x00 0x40 0x00 0x00 0x2a 0xd5 0x60 0x48 +# CHECK: memh(##42) = r21.h 0x2a 0xd5 0x40 0x48 -# CHECK: memh(##84) = r21 +# CHECK: memh(#84) = r21 0x2a 0xd5 0x60 0x48 -# CHECK: memh(##84) = r21.h +# CHECK: memh(#84) = r21.h 0x15 0xdf 0x51 0xa1 # CHECK: memh(r17+#42) = r31 0x15 0xdf 0x71 0xa1 @@ -138,8 +171,12 @@ # CHECK: memh(r17 ++ #10:circ(m1)) = r21.h 0x28 0xd5 0x51 0xab # CHECK: memh(r17++#10) = r21 +0x00 0x40 0x00 0x00 0xd5 0xff 0x51 0xad +# CHECK: memh(r17<<#3 + ##21) = r31 0x28 0xd5 0x71 0xab # CHECK: memh(r17++#10) = r21.h +0x00 0x40 0x00 0x00 0xd5 0xff 0x71 0xad +# CHECK: memh(r17<<#3 + ##21) = r31.h 0x00 0xf5 0x51 0xad # CHECK: memh(r17++m1) = r21 0x00 0xf5 0x71 0xad @@ -220,22 +257,48 @@ 0x03 0x40 0x45 0x85 0xaf 0xf5 0x71 0xab # CHECK: p3 = r5 # CHECK-NEXT: if (!p3.new) memh(r17++#10) = r21.h +0x00 0x40 0x00 0x00 0xd3 0xd5 0x42 0xaf +# CHECK: if (p3) memh(##42) = r21 +0x00 0x40 0x00 0x00 0xd3 0xd5 0x62 0xaf +# CHECK: if (p3) memh(##42) = r21.h +0x00 0x40 0x00 0x00 0xd7 0xd5 0x42 0xaf +# CHECK: if (!p3) memh(##42) = r21 +0x00 0x40 0x00 0x00 0xd7 0xd5 0x62 0xaf +# CHECK: if (!p3) memh(##42) = r21.h +0x03 0x40 0x45 0x85 0x00 0x40 0x00 0x00 0xd3 0xf5 0x42 0xaf +# CHECK: p3 = r5 +# CHECK-NEXT: if (p3.new) memh(##42) = r21 +0x03 0x40 0x45 0x85 0x00 0x40 0x00 0x00 0xd3 0xf5 0x62 0xaf +# CHECK: p3 = r5 +# CHECK-NEXT: if (p3.new) memh(##42) = r21.h +0x03 0x40 0x45 0x85 0x00 0x40 0x00 0x00 0xd7 0xf5 0x42 0xaf +# CHECK: p3 = r5 +# CHECK-NEXT: if (!p3.new) memh(##42) = r21 +0x03 0x40 0x45 0x85 0x00 0x40 0x00 0x00 0xd7 0xf5 0x62 0xaf +# CHECK: p3 = r5 +# CHECK-NEXT: if (!p3.new) memh(##42) = r21.h # Store word 0x9f 0xf5 0x91 0x3b # CHECK: memw(r17 + r21<<#3) = r31 0x9f 0xca 0x51 0x3c +# CHECK: memw(r17{{ *}}+{{ *}}#84)=#31 +0x15 0xdf 0x80 0x48 +# CHECK: memw(#84) = r31 +0x01 0x40 0x00 0x00 0x14 0xd5 0x80 0x48 +# CHECK: memw(##84) = r21 +0x9f 0xca 0x51 0x3c # CHECK: memw(r17+#84)=#31 0x15 0xdf 0x91 0xa1 # CHECK: memw(r17+#84) = r31 -0x14 0xd5 0x80 0x48 -# CHECK: memw(##80) = r21 0x02 0xf5 0x91 0xa9 # CHECK: memw(r17 ++ I:circ(m1)) = r21 0x28 0xf5 0x91 0xa9 # CHECK: memw(r17 ++ #20:circ(m1)) = r21 0x28 0xd5 0x91 0xab # CHECK: memw(r17++#20) = r21 +0x00 0x40 0x00 0x00 0xd5 0xff 0x91 0xad +# CHECK: memw(r17<<#3 + ##21) = r31 0x00 0xf5 0x91 0xad # CHECK: memw(r17++m1) = r21 0x00 0xf5 0x91 0xaf @@ -282,7 +345,17 @@ 0x03 0x40 0x45 0x85 0xab 0xf5 0x91 0xab # CHECK: p3 = r5 # CHECK-NEXT: if (p3.new) memw(r17++#20) = r21 +0x01 0x40 0x00 0x00 0xa3 0xd5 0x81 0xaf +# CHECK: if (p3) memw(##84) = r21 +0x01 0x40 0x00 0x00 0xa7 0xd5 0x81 0xaf +# CHECK: if (!p3) memw(##84) = r21 +0x03 0x40 0x45 0x85 0x01 0x40 0x00 0x00 0xa3 0xf5 0x81 0xaf +# CHECK: p3 = r5 +# CHECK-NEXT: if (p3.new) memw(##84) = r21 +0x03 0x40 0x45 0x85 0x01 0x40 0x00 0x00 0xa7 0xf5 0x81 0xaf +# CHECK: p3 = r5 +# CHECK-NEXT: if (!p3.new) memw(##84) = r21 # Allocate stack frame 0x1f 0xc0 0x9d 0xa0 -# CHECK: allocframe(#248) \ No newline at end of file +# CHECK: allocframe(#248) diff --git a/test/MC/Disassembler/Hexagon/too_many_instructions.txt b/test/MC/Disassembler/Hexagon/too_many_instructions.txt new file mode 100644 index 00000000000..2aaa22d37f9 --- /dev/null +++ b/test/MC/Disassembler/Hexagon/too_many_instructions.txt @@ -0,0 +1,4 @@ +# RUN: llvm-mc -triple=hexagon -disassemble < %s 2>&1 | FileCheck %s + +#CHECK: warning: invalid instruction encoding +0x00 0x40 0x00 0x7f 0x00 0x40 0x00 0x7f 0x00 0x40 0x00 0x7f 0x00 0x40 0x00 0x7f 0x00 0xc0 0x00 0x7f \ No newline at end of file diff --git a/test/MC/Disassembler/Hexagon/too_many_loop_ends.txt b/test/MC/Disassembler/Hexagon/too_many_loop_ends.txt new file mode 100644 index 00000000000..55a6f0b3692 --- /dev/null +++ b/test/MC/Disassembler/Hexagon/too_many_loop_ends.txt @@ -0,0 +1,4 @@ +# RUN: llvm-mc -triple=hexagon -disassemble < %s 2>&1 | FileCheck %s + +#CHECK: warning: invalid instruction encoding +0x00 0x80 0x00 0x7f 0x00 0x80 0x00 0x7f 0x00 0x80 0x00 0x7f 0x00 0xc0 0x00 0x7f \ No newline at end of file diff --git a/test/MC/Disassembler/Hexagon/unextendable.txt b/test/MC/Disassembler/Hexagon/unextendable.txt new file mode 100644 index 00000000000..377c123177c --- /dev/null +++ b/test/MC/Disassembler/Hexagon/unextendable.txt @@ -0,0 +1,9 @@ +# RUN: llvm-mc -triple=hexagon -disassemble < %s 2>&1 | FileCheck %s + +#Invalid immediate extend duplex load/load +#CHECK: warning: invalid instruction encoding +0xfe 0x40 0x00 0x00 0x11 0x00 0x00 0x00 + +#Invalid immediate extend barrier +#CHECK: warning: invalid instruction encoding +0xfe 0x40 0x00 0x00 0x00 0xc0 0x00 0xa8 \ No newline at end of file diff --git a/test/MC/Hexagon/instructions/alu32_alu.s b/test/MC/Hexagon/instructions/alu32_alu.s new file mode 100644 index 00000000000..4b3256be073 --- /dev/null +++ b/test/MC/Hexagon/instructions/alu32_alu.s @@ -0,0 +1,84 @@ +# RUN: llvm-mc -triple hexagon -filetype=obj %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.1.1 ALU32/ALU + +# Add +# CHECK: f1 c3 15 b0 +r17 = add(r21, #31) +# CHECK: 11 df 15 f3 +r17 = add(r21, r31) +# CHECK: 11 df 55 f6 +r17 = add(r21, r31):sat + +# And +# CHECK: f1 c3 15 76 +r17 = and(r21, #31) +# CHECK: f1 c3 95 76 +r17 = or(r21, #31) +# CHECK: 11 df 15 f1 +r17 = and(r21, r31) +# CHECK: 11 df 35 f1 +r17 = or(r21, r31) +# CHECK: 11 df 75 f1 +r17 = xor(r21, r31) +# CHECK: 11 d5 9f f1 +r17 = and(r21, ~r31) +# CHECK: 11 d5 bf f1 +r17 = or(r21, ~r31) + +# Nop +# CHECK: 00 c0 00 7f +nop + +# Subtract +# CHECK: b1 c2 5f 76 +r17 = sub(#21, r31) +# CHECK: 11 df 35 f3 +r17 = sub(r31, r21) +# CHECK: 11 df d5 f6 +r17 = sub(r31, r21):sat + +# Sign extend +# CHECK: 11 c0 bf 70 +r17 = sxtb(r31) + +# Transfer immediate +# CHECK: 15 c0 31 72 +r17.h = #21 +# CHECK: 15 c0 31 71 +r17.l = #21 +# CHECK: f1 ff 5f 78 +r17 = #32767 +# CHECK: f1 ff df 78 +r17 = #-1 + +# Transfer register +# CHECK: 11 c0 75 70 +r17 = r21 + +# Vector add halfwords +# CHECK: 11 df 15 f6 +r17 = vaddh(r21, r31) +# CHECK: 11 df 35 f6 +r17 = vaddh(r21, r31):sat +# CHECK: 11 df 75 f6 +r17 = vadduh(r21, r31):sat + +# Vector average halfwords +# CHECK: 11 df 15 f7 +r17 = vavgh(r21, r31) +# CHECK: 11 df 35 f7 +r17 = vavgh(r21, r31):rnd +# CHECK: 11 df 75 f7 +r17 = vnavgh(r31, r21) + +# Vector subtract halfwords +# CHECK: 11 df 95 f6 +r17 = vsubh(r31, r21) +# CHECK: 11 df b5 f6 +r17 = vsubh(r31, r21):sat +# CHECK: 11 df f5 f6 +r17 = vsubuh(r31, r21):sat + +# Zero extend +# CHECK: 11 c0 d5 70 +r17 = zxth(r21) diff --git a/test/MC/Hexagon/instructions/alu32_perm.s b/test/MC/Hexagon/instructions/alu32_perm.s new file mode 100644 index 00000000000..8410cb9128a --- /dev/null +++ b/test/MC/Hexagon/instructions/alu32_perm.s @@ -0,0 +1,40 @@ +# RUN: llvm-mc -triple hexagon -filetype=obj %s -o - | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.1.2 ALU32/PERM + +# Combine words in to doublewords +# CHECK: 11 df 95 f3 +r17 = combine(r31.h, r21.h) +# CHECK: 11 df b5 f3 +r17 = combine(r31.h, r21.l) +# CHECK: 11 df d5 f3 +r17 = combine(r31.l, r21.h) +# CHECK: 11 df f5 f3 +r17 = combine(r31.l, r21.l) +# CHECK: b0 e2 0f 7c +r17:16 = combine(#21, #31) +# CHECK: b0 e2 3f 73 +r17:16 = combine(#21, r31) +# CHECK: f0 e3 15 73 +r17:16 = combine(r21, #31) +# CHECK: 10 df 15 f5 +r17:16 = combine(r21, r31) + +# Mux +# CHECK: f1 c3 75 73 +r17 = mux(p3, r21, #31) +# CHECK: b1 c2 ff 73 +r17 = mux(p3, #21, r31) +# CHECK: b1 e2 8f 7b +r17 = mux(p3, #21, #31) +# CHECK: 71 df 15 f4 +r17 = mux(p3, r21, r31) + +# Shift word by 16 +# CHECK: 11 c0 15 70 +r17 = aslh(r21) +# CHECK: 11 c0 35 70 +r17 = asrh(r21) + +# Pack high and low halfwords +# CHECK: 10 df 95 f5 +r17:16 = packhl(r21, r31) diff --git a/test/MC/Hexagon/instructions/alu32_pred.s b/test/MC/Hexagon/instructions/alu32_pred.s new file mode 100644 index 00000000000..e5fded0a369 --- /dev/null +++ b/test/MC/Hexagon/instructions/alu32_pred.s @@ -0,0 +1,222 @@ +# RUN: llvm-mc -triple hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.1.3 ALU32/PRED + +# Conditional add +# CHECK: f1 c3 75 74 +if (p3) r17 = add(r21, #31) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 e3 75 74 +{ p3 = r5 + if (p3.new) r17 = add(r21, #31) } +# CHECK: f1 c3 f5 74 +if (!p3) r17 = add(r21, #31) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 e3 f5 74 +{ p3 = r5 + if (!p3.new) r17 = add(r21, #31) } +# CHECK: 71 df 15 fb +if (p3) r17 = add(r21, r31) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 71 ff 15 fb +{ p3 = r5 + if (p3.new) r17 = add(r21, r31) } +# CHECK: f1 df 15 fb +if (!p3) r17 = add(r21, r31) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 15 fb +{ p3 = r5 + if (!p3.new) r17 = add(r21, r31) } + +# Conditional shift halfword +# CHECK: 11 e3 15 70 +if (p3) r17 = aslh(r21) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 e7 15 70 +{ p3 = r5 + if (p3.new) r17 = aslh(r21) } +# CHECK: 11 eb 15 70 +if (!p3) r17 = aslh(r21) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 ef 15 70 +{ p3 = r5 + if (!p3.new) r17 = aslh(r21) } +# CHECK: 11 e3 35 70 +if (p3) r17 = asrh(r21) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 e7 35 70 +{ p3 = r5 + if (p3.new) r17 = asrh(r21) } +# CHECK: 11 eb 35 70 +if (!p3) r17 = asrh(r21) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 ef 35 70 +{ p3 = r5 + if (!p3.new) r17 = asrh(r21) } + +# Conditional combine +# CHECK: 70 df 15 fd +if (p3) r17:16 = combine(r21, r31) +# CHECK: f0 df 15 fd +if (!p3) r17:16 = combine(r21, r31) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 70 ff 15 fd +{ p3 = r5 + if (p3.new) r17:16 = combine(r21, r31) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f0 ff 15 fd +{ p3 = r5 + if (!p3.new) r17:16 = combine(r21, r31) } + +# Conditional logical operations +# CHECK: 71 df 15 f9 +if (p3) r17 = and(r21, r31) +# CHECK: f1 df 15 f9 +if (!p3) r17 = and(r21, r31) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 71 ff 15 f9 +{ p3 = r5 + if (p3.new) r17 = and(r21, r31) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 15 f9 +{ p3 = r5 + if (!p3.new) r17 = and(r21, r31) } +# CHECK: 71 df 35 f9 +if (p3) r17 = or(r21, r31) +# CHECK: f1 df 35 f9 +if (!p3) r17 = or(r21, r31) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 71 ff 35 f9 +{ p3 = r5 + if (p3.new) r17 = or(r21, r31) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 35 f9 +{ p3 = r5 + if (!p3.new) r17 = or(r21, r31) } +# CHECK: 71 df 75 f9 +if (p3) r17 = xor(r21, r31) +# CHECK: f1 df 75 f9 +if (!p3) r17 = xor(r21, r31) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 71 ff 75 f9 +{ p3 = r5 + if (p3.new) r17 = xor(r21, r31) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 75 f9 +{ p3 = r5 + if (!p3.new) r17 = xor(r21, r31) } + +# Conditional subtract +# CHECK: 71 df 35 fb +if (p3) r17 = sub(r31, r21) +# CHECK: f1 df 35 fb +if (!p3) r17 = sub(r31, r21) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 71 ff 35 fb +{ p3 = r5 + if (p3.new) r17 = sub(r31, r21) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 35 fb +{ p3 = r5 + if (!p3.new) r17 = sub(r31, r21) } + +# Conditional sign extend +# CHECK: 11 e3 b5 70 +if (p3) r17 = sxtb(r21) +# CHECK: 11 eb b5 70 +if (!p3) r17 = sxtb(r21) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 e7 b5 70 +{ p3 = r5 + if (p3.new) r17 = sxtb(r21) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 ef b5 70 +{ p3 = r5 + if (!p3.new) r17 = sxtb(r21) } +# CHECK: 11 e3 f5 70 +if (p3) r17 = sxth(r21) +# CHECK: 11 eb f5 70 +if (!p3) r17 = sxth(r21) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 e7 f5 70 +{ p3 = r5 + if (p3.new) r17 = sxth(r21) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 ef f5 70 +{ p3 = r5 + if (!p3.new) r17 = sxth(r21) } + +# Conditional transfer +# CHECK: b1 c2 60 7e +if (p3) r17 = #21 +# CHECK: b1 c2 e0 7e +if (!p3) r17 = #21 +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 e2 60 7e +{ p3 = r5 + if (p3.new) r17 = #21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 e2 e0 7e +{ p3 = r5 + if (!p3.new) r17 = #21 } + +# Conditional zero extend +# CHECK: 11 e3 95 70 +if (p3) r17 = zxtb(r21) +# CHECK: 11 eb 95 70 +if (!p3) r17 = zxtb(r21) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 e7 95 70 +{ p3 = r5 + if (p3.new) r17 = zxtb(r21) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 ef 95 70 +{ p3 = r5 + if (!p3.new) r17 = zxtb(r21) } +# CHECK: 11 e3 d5 70 +if (p3) r17 = zxth(r21) +# CHECK: 11 eb d5 70 +if (!p3) r17 = zxth(r21) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 e7 d5 70 +{ p3 = r5 + if (p3.new) r17 = zxth(r21) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 11 ef d5 70 +{ p3 = r5 + if (!p3.new) r17 = zxth(r21) } + +# Compare +# CHECK: e3 c3 15 75 +p3 = cmp.eq(r21, #31) +# CHECK: f3 c3 15 75 +p3 = !cmp.eq(r21, #31) +# CHECK: e3 c3 55 75 +p3 = cmp.gt(r21, #31) +# CHECK: f3 c3 55 75 +p3 = !cmp.gt(r21, #31) +# CHECK: e3 c3 95 75 +p3 = cmp.gtu(r21, #31) +# CHECK: f3 c3 95 75 +p3 = !cmp.gtu(r21, #31) +# CHECK: 03 df 15 f2 +p3 = cmp.eq(r21, r31) +# CHECK: 13 df 15 f2 +p3 = !cmp.eq(r21, r31) +# CHECK: 03 df 55 f2 +p3 = cmp.gt(r21, r31) +# CHECK: 13 df 55 f2 +p3 = !cmp.gt(r21, r31) +# CHECK: 03 df 75 f2 +p3 = cmp.gtu(r21, r31) +# CHECK: 13 df 75 f2 +p3 = !cmp.gtu(r21, r31) + +# Compare to general register +# CHECK: f1 e3 55 73 +r17 = cmp.eq(r21, #31) +# CHECK: f1 e3 75 73 +r17 = !cmp.eq(r21, #31) +# CHECK: 11 df 55 f3 +r17 = cmp.eq(r21, r31) +# CHECK: 11 df 75 f3 +r17 = !cmp.eq(r21, r31) diff --git a/test/MC/Hexagon/instructions/cr.s b/test/MC/Hexagon/instructions/cr.s new file mode 100644 index 00000000000..4cc21551865 --- /dev/null +++ b/test/MC/Hexagon/instructions/cr.s @@ -0,0 +1,78 @@ +# RUN: llvm-mc --triple hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.2 CR + +# Corner detection acceleration +# CHECK: 93 e1 12 6b +p3 = !fastcorner9(p2, p1) +# CHECK: 91 e3 02 6b +p1 = fastcorner9(p2, p3) + +# Logical reductions on predicates +# CHECK: 01 c0 82 6b +p1 = any8(p2) +# CHECK: 01 c0 a2 6b +p1 = all8(p2) + +# Looping instructions +# CHECK: 00 c0 15 60 +loop0(0, r21) +# CHECK: 00 c0 35 60 +loop1(0, r21) +# CHECK: 60 c0 00 69 +loop0(0, #12) +# CHECK: 60 c0 20 69 +loop1(0, #12) + +# Add to PC +# CHECK: 91 ca 49 6a +r17 = add(pc, #21) + +# Pipelined loop instructions +# CHECK: 00 c0 b5 60 +p3 = sp1loop0(0, r21) +# CHECK: 00 c0 d5 60 +p3 = sp2loop0(0, r21) +# CHECK: 00 c0 f5 60 +p3 = sp3loop0(0, r21) +# CHECK: a1 c0 a0 69 +p3 = sp1loop0(0, #21) +# CHECK: a1 c0 c0 69 +p3 = sp2loop0(0, #21) +# CHECK: a1 c0 e0 69 +p3 = sp3loop0(0, #21) + +# Logical operations on predicates +# CHECK: 01 c3 02 6b +p1 = and(p3, p2) +# CHECK: c1 c3 12 6b +p1 = and(p2, and(p3, p3)) +# CHECK: 01 c3 22 6b +p1 = or(p3, p2) +# CHECK: c1 c3 32 6b +p1 = and(p2, or(p3, p3)) +# CHECK: 01 c3 42 6b +p1 = xor(p2, p3) +# CHECK: c1 c3 52 6b +p1 = or(p2, and(p3, p3)) +# CHECK: 01 c2 63 6b +p1 = and(p2, !p3) +# CHECK: c1 c3 72 6b +p1 = or(p2, or(p3, p3)) +# CHECK: c1 c3 92 6b +p1 = and(p2, and(p3, !p3)) +# CHECK: c1 c3 b2 6b +p1 = and(p2, or(p3, !p3)) +# CHECK: 01 c0 c2 6b +p1 = not(p2) +# CHECK: c1 c3 d2 6b +p1 = or(p2, and(p3, !p3)) +# CHECK: 01 c2 e3 6b +p1 = or(p2, !p3) +# CHECK: c1 c3 f2 6b +p1 = or(p2, or(p3, !p3)) + +# User control register transfer +# CHECK: 0d c0 35 62 +cs1 = r21 +# CHECK: 11 c0 0d 6a +r17 = cs1 diff --git a/test/MC/Hexagon/instructions/j.s b/test/MC/Hexagon/instructions/j.s new file mode 100644 index 00000000000..720edd62a90 --- /dev/null +++ b/test/MC/Hexagon/instructions/j.s @@ -0,0 +1,207 @@ +# RUN: llvm-mc -triple hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.4 J +# XFAIL: * + +# Call subroutine +# CHECK: 00 c0 00 5a +call 0 +# CHECK: 00 c3 00 5d +if (p3) call 0 +# CHECK: 00 c3 20 5d +if (!p3) call 0 + +# Compare and jump +# CHECK: 00 c0 89 11 +{ p0 = cmp.eq(r17,#-1); if (p0.new) jump:nt 0 } +# CHECK: 00 c1 89 11 +{ p0 = cmp.gt(r17,#-1); if (p0.new) jump:nt 0 } +# CHECK: 00 c3 89 11 +{ p0 = tstbit(r17, #0); if (p0.new) jump:nt 0 } +# CHECK: 00 e0 89 11 +{ p0 = cmp.eq(r17,#-1); if (p0.new) jump:t 0 } +# CHECK: 00 e1 89 11 +{ p0 = cmp.gt(r17,#-1); if (p0.new) jump:t 0 } +# CHECK: 00 e3 89 11 +{ p0 = tstbit(r17, #0); if (p0.new) jump:t 0 } +# CHECK: 00 c0 c9 11 +{ p0 = cmp.eq(r17,#-1); if (!p0.new) jump:nt 0 } +# CHECK: 00 c1 c9 11 +{ p0 = cmp.gt(r17,#-1); if (!p0.new) jump:nt 0 } +# CHECK: 00 c3 c9 11 +{ p0 = tstbit(r17, #0); if (!p0.new) jump:nt 0 } +# CHECK: 00 e0 c9 11 +{ p0 = cmp.eq(r17,#-1); if (!p0.new) jump:t 0 } +# CHECK: 00 e1 c9 11 +{ p0 = cmp.gt(r17,#-1); if (!p0.new) jump:t 0 } +# CHECK: 00 e3 c9 11 +{ p0 = tstbit(r17, #0); if (!p0.new) jump:t 0 } +# CHECK: 00 d5 09 10 +{ p0 = cmp.eq(r17, #21); if (p0.new) jump:nt 0 } +# CHECK: 00 f5 09 10 +{ p0 = cmp.eq(r17, #21); if (p0.new) jump:t 0 } +# CHECK: 00 d5 49 10 +{ p0 = cmp.eq(r17, #21); if (!p0.new) jump:nt 0 } +# CHECK: 00 f5 49 10 +{ p0 = cmp.eq(r17, #21); if (!p0.new) jump:t 0 } +# CHECK: 00 d5 89 10 +{ p0 = cmp.gt(r17, #21); if (p0.new) jump:nt 0 } +# CHECK: 00 f5 89 10 +{ p0 = cmp.gt(r17, #21); if (p0.new) jump:t 0 } +# CHECK: 00 d5 c9 10 +{ p0 = cmp.gt(r17, #21); if (!p0.new) jump:nt 0 } +# CHECK: 00 f5 c9 10 +{ p0 = cmp.gt(r17, #21); if (!p0.new) jump:t 0 } +# CHECK: 00 d5 09 11 +{ p0 = cmp.gtu(r17, #21); if (p0.new) jump:nt 0 } +# CHECK: 00 f5 09 11 +{ p0 = cmp.gtu(r17, #21); if (p0.new) jump:t 0 } +# CHECK: 00 d5 49 11 +{ p0 = cmp.gtu(r17, #21); if (!p0.new) jump:nt 0 } +# CHECK: 00 f5 49 11 +{ p0 = cmp.gtu(r17, #21); if (!p0.new) jump:t 0 } +# CHECK: 00 c0 89 13 +{ p1 = cmp.eq(r17,#-1); if (p1.new) jump:nt 0 } +# CHECK: 00 c1 89 13 +{ p1 = cmp.gt(r17,#-1); if (p1.new) jump:nt 0 } +# CHECK: 00 c3 89 13 +{ p1 = tstbit(r17, #0); if (p1.new) jump:nt 0 } +# CHECK: 00 e0 89 13 +{ p1 = cmp.eq(r17,#-1); if (p1.new) jump:t 0 } +# CHECK: 00 e1 89 13 +{ p1 = cmp.gt(r17,#-1); if (p1.new) jump:t 0 } +# CHECK: 00 e3 89 13 +{ p1 = tstbit(r17, #0); if (p1.new) jump:t 0 } +# CHECK: 00 c0 c9 13 +{ p1 = cmp.eq(r17,#-1); if (!p1.new) jump:nt 0 } +# CHECK: 00 c1 c9 13 +{ p1 = cmp.gt(r17,#-1); if (!p1.new) jump:nt 0 } +# CHECK: 00 c3 c9 13 +{ p1 = tstbit(r17, #0); if (!p1.new) jump:nt 0 } +# CHECK: 00 e0 c9 13 +{ p1 = cmp.eq(r17,#-1); if (!p1.new) jump:t 0 } +# CHECK: 00 e1 c9 13 +{ p1 = cmp.gt(r17,#-1); if (!p1.new) jump:t 0 } +# CHECK: 00 e3 c9 13 +{ p1 = tstbit(r17, #0); if (!p1.new) jump:t 0 } +# CHECK: 00 d5 09 12 +{ p1 = cmp.eq(r17, #21); if (p1.new) jump:nt 0 } +# CHECK: 00 f5 09 12 +{ p1 = cmp.eq(r17, #21); if (p1.new) jump:t 0 } +# CHECK: 00 d5 49 12 +{ p1 = cmp.eq(r17, #21); if (!p1.new) jump:nt 0 } +# CHECK: 00 f5 49 12 +{ p1 = cmp.eq(r17, #21); if (!p1.new) jump:t 0 } +# CHECK: 00 d5 89 12 +{ p1 = cmp.gt(r17, #21); if (p1.new) jump:nt 0 } +# CHECK: 00 f5 89 12 +{ p1 = cmp.gt(r17, #21); if (p1.new) jump:t 0 } +# CHECK: 00 d5 c9 12 +{ p1 = cmp.gt(r17, #21); if (!p1.new) jump:nt 0 } +# CHECK: 00 f5 c9 12 +{ p1 = cmp.gt(r17, #21); if (!p1.new) jump:t 0 } +# CHECK: 00 d5 09 13 +{ p1 = cmp.gtu(r17, #21); if (p1.new) jump:nt 0 } +# CHECK: 00 f5 09 13 +{ p1 = cmp.gtu(r17, #21); if (p1.new) jump:t 0 } +# CHECK: 00 d5 49 13 +{ p1 = cmp.gtu(r17, #21); if (!p1.new) jump:nt 0 } +# CHECK: 00 f5 49 13 +{ p1 = cmp.gtu(r17, #21); if (!p1.new) jump:t 0 } +# CHECK: 00 cd 09 14 +{ p0 = cmp.eq(r17, r21); if (p0.new) jump:nt 0 } +# CHECK: 00 dd 09 14 +{ p1 = cmp.eq(r17, r21); if (p1.new) jump:nt 0 } +# CHECK: 00 ed 09 14 +{ p0 = cmp.eq(r17, r21); if (p0.new) jump:t 0 } +# CHECK: 00 fd 09 14 +{ p1 = cmp.eq(r17, r21); if (p1.new) jump:t 0 } +# CHECK: 00 cd 49 14 +{ p0 = cmp.eq(r17, r21); if (!p0.new) jump:nt 0 } +# CHECK: 00 dd 49 14 +{ p1 = cmp.eq(r17, r21); if (!p1.new) jump:nt 0 } +# CHECK: 00 ed 49 14 +{ p0 = cmp.eq(r17, r21); if (!p0.new) jump:t 0 } +# CHECK: 00 fd 49 14 +{ p1 = cmp.eq(r17, r21); if (!p1.new) jump:t 0 } +# CHECK: 00 cd 89 14 +{ p0 = cmp.gt(r17, r21); if (p0.new) jump:nt 0 } +# CHECK: 00 dd 89 14 +{ p1 = cmp.gt(r17, r21); if (p1.new) jump:nt 0 } +# CHECK: 00 ed 89 14 +{ p0 = cmp.gt(r17, r21); if (p0.new) jump:t 0 } +# CHECK: 00 fd 89 14 +{ p1 = cmp.gt(r17, r21); if (p1.new) jump:t 0 } +# CHECK: 00 cd c9 14 +{ p0 = cmp.gt(r17, r21); if (!p0.new) jump:nt 0 } +# CHECK: 00 dd c9 14 +{ p1 = cmp.gt(r17, r21); if (!p1.new) jump:nt 0 } +# CHECK: 00 ed c9 14 +{ p0 = cmp.gt(r17, r21); if (!p0.new) jump:t 0 } +# CHECK: 00 fd c9 14 +{ p1 = cmp.gt(r17, r21); if (!p1.new) jump:t 0 } +# CHECK: 00 cd 09 15 +{ p0 = cmp.gtu(r17, r21); if (p0.new) jump:nt 0 } +# CHECK: 00 dd 09 15 +{ p1 = cmp.gtu(r17, r21); if (p1.new) jump:nt 0 } +# CHECK: 00 ed 09 15 +{ p0 = cmp.gtu(r17, r21); if (p0.new) jump:t 0 } +# CHECK: 00 fd 09 15 +{ p1 = cmp.gtu(r17, r21); if (p1.new) jump:t 0 } +# CHECK: 00 cd 49 15 +{ p0 = cmp.gtu(r17, r21); if (!p0.new) jump:nt 0 } +# CHECK: 00 dd 49 15 +{ p1 = cmp.gtu(r17, r21); if (!p1.new) jump:nt 0 } +# CHECK: 00 ed 49 15 +{ p0 = cmp.gtu(r17, r21); if (!p0.new) jump:t 0 } +# CHECK: 00 fd 49 15 +{ p1 = cmp.gtu(r17, r21); if (!p1.new) jump:t 0 } + +# Jump to address +# CHECK: 00 c0 00 58 +jump 0 +# CHECK: 00 c3 00 5c +if (p3) jump 0 +# CHECK: 00 c3 20 5c +if (!p3) jump 0 + +# Jump to address conditioned on new predicate +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 cb 00 5c +{ p3 = r5 + if (p3.new) jump:nt 0 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 db 00 5c +{ p3 = r5 + if (p3.new) jump:t 0 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 cb 20 5c +{ p3 = r5 + if (!p3.new) jump:nt 0 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 db 20 5c +{ p3 = r5 + if (!p3.new) jump:t 0 } + +# Jump to address conditioned on register value +# CHECK: 00 c0 11 61 +if (r17!=#0) jump:nt 0 +# CHECK: 00 d0 11 61 +if (r17!=#0) jump:t 0 +# CHECK: 00 c0 51 61 +if (r17>=#0) jump:nt 0 +# CHECK: 00 d0 51 61 +if (r17>=#0) jump:t 0 +# CHECK: 00 c0 91 61 +if (r17==#0) jump:nt 0 +# CHECK: 00 d0 91 61 +if (r17==#0) jump:t 0 +# CHECK: 00 c0 d1 61 +if (r17<=#0) jump:nt 0 +# CHECK: 00 d0 d1 61 +if (r17<=#0) jump:t 0 + +# Transfer and jump +# CHECK: 00 d5 09 16 +{ r17 = #21 ; jump 0} +# CHECK: 00 c9 0d 17 +{ r17 = r21 ; jump 0 } diff --git a/test/MC/Hexagon/instructions/jr.s b/test/MC/Hexagon/instructions/jr.s new file mode 100644 index 00000000000..f4f32450f34 --- /dev/null +++ b/test/MC/Hexagon/instructions/jr.s @@ -0,0 +1,38 @@ +# RUN: llvm-mc -triple hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.3 JR + +# Call subroutine from register +# CHECK: 00 c0 b5 50 +callr r21 +# CHECK: 00 c1 15 51 +if (p1) callr r21 +# CHECK: 00 c3 35 51 +if (!p3) callr r21 + +# Hint an indirect jump address +# CHECK: 00 c0 b5 52 +hintjr(r21) + +# Jump to address from register +# CHECK: 00 c0 95 52 +jumpr r21 +# CHECK: 00 c1 55 53 +if (p1) jumpr r21 +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 cb 55 53 +{ p3 = r5 + if (p3.new) jumpr:nt r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 db 55 53 +{ p3 = r5 + if (p3.new) jumpr:t r21 } +# CHECK: 00 c3 75 53 +if (!p3) jumpr r21 +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 cb 75 53 +{ p3 = r5 + if (!p3.new) jumpr:nt r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 db 75 53 +{ p3 = r5 + if (!p3.new) jumpr:t r21 } diff --git a/test/MC/Hexagon/instructions/ld.s b/test/MC/Hexagon/instructions/ld.s new file mode 100644 index 00000000000..cbfa7799f83 --- /dev/null +++ b/test/MC/Hexagon/instructions/ld.s @@ -0,0 +1,499 @@ +# RUN: llvm-mc -triple hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.5 LD +# XFAIL: * + +# Load doubleword +# CHECK: 90 ff d5 3a +r17:16 = memd(r21 + r31<<#3) +# CHECK: b0 c2 c0 49 +r17:16 = memd(#168) +# CHECK: 02 40 00 00 +# CHECK-NEXT: 10 c5 c0 49 +r17:16 = memd(##168) +# CHECK: d0 c0 d5 91 +r17:16 = memd(r21 + #48) +# CHECK: b0 e0 d5 99 +r17:16 = memd(r21 ++ #40:circ(m1)) +# CHECK: 10 e2 d5 99 +r17:16 = memd(r21 ++ I:circ(m1)) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 70 d7 d5 9b +r17:16 = memd(r21 = ##31) +# CHECK: b0 c0 d5 9b +r17:16 = memd(r21++#40) +# CHECK: 10 e0 d5 9d +r17:16 = memd(r21++m1) +# CHECK: 10 e0 d5 9f +r17:16 = memd(r21 ++ m1:brev) + +# Load doubleword conditionally +# CHECK: f0 ff d5 30 +if (p3) r17:16 = memd(r21+r31<<#3) +# CHECK: f0 ff d5 31 +if (!p3) r17:16 = memd(r21+r31<<#3) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f0 ff d5 32 +{ p3 = r5 + if (p3.new) r17:16 = memd(r21+r31<<#3) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f0 ff d5 33 +{ p3 = r5 + if (!p3.new) r17:16 = memd(r21+r31<<#3) } +# CHECK: 70 d8 d5 41 +if (p3) r17:16 = memd(r21 + #24) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 70 d8 d5 43 +{ p3 = r5 + if (p3.new) r17:16 = memd(r21 + #24) } +# CHECK: 70 d8 d5 45 +if (!p3) r17:16 = memd(r21 + #24) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 70 d8 d5 47 +{ p3 = r5 + if (!p3.new) r17:16 = memd(r21 + #24) } +# CHECK: b0 e6 d5 9b +if (p3) r17:16 = memd(r21++#40) +# CHECK: b0 ee d5 9b +if (!p3) r17:16 = memd(r21++#40) +# CHECK: 03 40 45 85 +# CHECK-NEXT: b0 f6 d5 9b +{ p3 = r5 + if (p3.new) r17:16 = memd(r21++#40) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: b0 fe d5 9b +{ p3 = r5 + if (!p3.new) r17:16 = memd(r21++#40) } + +# Load byte +# CHECK: 91 ff 15 3a +r17 = memb(r21 + r31<<#3) +# CHECK: b1 c2 00 49 +r17 = memb(#21) +# CHECK: 00 40 00 00 +# CHECK-NEXT: b1 c2 00 49 +r17 = memb(##21) +# CHECK: f1 c3 15 91 +r17 = memb(r21 + #31) +# CHECK: b1 e0 15 99 +r17 = memb(r21 ++ #5:circ(m1)) +# CHECK: 11 e2 15 99 +r17 = memb(r21 ++ I:circ(m1)) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 71 d7 15 9b +r17 = memb(r21 = ##31) +# CHECK: b1 c0 15 9b +r17 = memb(r21++#5) +# CHECK: 11 e0 15 9d +r17 = memb(r21++m1) +# CHECK: 11 e0 15 9f +r17 = memb(r21 ++ m1:brev) + +# Load byte conditionally +# CHECK: f1 ff 15 30 +if (p3) r17 = memb(r21+r31<<#3) +# CHECK: f1 ff 15 31 +if (!p3) r17 = memb(r21+r31<<#3) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 15 32 +{ p3 = r5 + if (p3.new) r17 = memb(r21+r31<<#3) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 15 33 +{ p3 = r5 + if (!p3.new) r17 = memb(r21+r31<<#3) } +# CHECK: 91 dd 15 41 +if (p3) r17 = memb(r21 + #44) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 91 dd 15 43 +{ p3 = r5 + if (p3.new) r17 = memb(r21 + #44) } +# CHECK: 91 dd 15 45 +if (!p3) r17 = memb(r21 + #44) +# CHECK: 03 40 45 85 +# CHECK-NEXT: 91 dd 15 47 +{ p3 = r5 + if (!p3.new) r17 = memb(r21 + #44) } +# CHECK: b1 e6 15 9b +if (p3) r17 = memb(r21++#5) +# CHECK: b1 ee 15 9b +if (!p3) r17 = memb(r21++#5) +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 f6 15 9b +{ p3 = r5 + if (p3.new) r17 = memb(r21++#5) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 fe 15 9b +{ p3 = r5 + if (!p3.new) r17 = memb(r21++#5) } + +# Load byte into shifted vector +# CHECK: f0 c3 95 90 +r17:16 = memb_fifo(r21 + #31) +# CHECK: b0 e0 95 98 +r17:16 = memb_fifo(r21 ++ #5:circ(m1)) +# CHECK: 10 e2 95 98 +r17:16 = memb_fifo(r21 ++ I:circ(m1)) + +# Load half into shifted vector +# CHECK: f0 c3 55 90 +r17:16 = memh_fifo(r21 + #62) +# CHECK: b0 e0 55 98 +r17:16 = memh_fifo(r21 ++ #10:circ(m1)) +# CHECK: 10 e2 55 98 +r17:16 = memh_fifo(r21 ++ I:circ(m1)) + +# Load halfword +# CHECK: 91 ff 55 3a +r17 = memh(r21 + r31<<#3) +# CHECK: b1 c2 40 49 +r17 = memh(#42) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 51 c5 40 49 +r17 = memh(##42) +# CHECK: f1 c3 55 91 +r17 = memh(r21 + #62) +# CHECK: b1 e0 55 99 +r17 = memh(r21 ++ #10:circ(m1)) +# CHECK: 11 e2 55 99 +r17 = memh(r21 ++ I:circ(m1)) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 71 d7 55 9b +r17 = memh(r21 = ##31) +# CHECK: b1 c0 55 9b +r17 = memh(r21++#10) +# CHECK: 11 e0 55 9d +r17 = memh(r21++m1) +# CHECK: 11 e0 55 9f +r17 = memh(r21 ++ m1:brev) + +# Load halfword conditionally +# CHECK: f1 ff 55 30 +if (p3) r17 = memh(r21+r31<<#3) +# CHECK: f1 ff 55 31 +if (!p3) r17 = memh(r21+r31<<#3) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 55 32 +{ p3 = r5 + if (p3.new) r17 = memh(r21+r31<<#3) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 55 33 +{ p3 = r5 + if (!p3.new) r17 = memh(r21+r31<<#3) } +# CHECK: b1 e6 55 9b +if (p3) r17 = memh(r21++#10) +# CHECK: b1 ee 55 9b +if (!p3) r17 = memh(r21++#10) +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 f6 55 9b +{ p3 = r5 + if (p3.new) r17 = memh(r21++#10) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 fe 55 9b +{ p3 = r5 + if (!p3.new) r17 = memh(r21++#10) } +# CHECK: f1 db 55 41 +if (p3) r17 = memh(r21 + #62) +# CHECK: f1 db 55 45 +if (!p3) r17 = memh(r21 + #62) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 db 55 43 +{ p3 = r5 + if (p3.new) r17 = memh(r21 + #62) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 db 55 47 +{ p3 = r5 + if (!p3.new) r17 = memh(r21 + #62) } + +# Load unsigned byte +# CHECK: 91 ff 35 3a +r17 = memub(r21 + r31<<#3) +# CHECK: b1 c2 20 49 +r17 = memub(#21) +# CHECK: 00 40 00 00 +# CHECK-NEXT: b1 c2 20 49 +r17 = memub(##21) +# CHECK: f1 c3 35 91 +r17 = memub(r21 + #31) +# CHECK: b1 e0 35 99 +r17 = memub(r21 ++ #5:circ(m1)) +# CHECK: 11 e2 35 99 +r17 = memub(r21 ++ I:circ(m1)) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 71 d7 35 9b +r17 = memub(r21 = ##31) +# CHECK: b1 c0 35 9b +r17 = memub(r21++#5) +# CHECK: 11 e0 35 9d +r17 = memub(r21++m1) +# CHECK: 11 e0 35 9f +r17 = memub(r21 ++ m1:brev) + +# Load unsigned byte conditionally +# CHECK: f1 ff 35 30 +if (p3) r17 = memub(r21+r31<<#3) +# CHECK: f1 ff 35 31 +if (!p3) r17 = memub(r21+r31<<#3) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 35 32 +{ p3 = r5 + if (p3.new) r17 = memub(r21+r31<<#3) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 35 33 +{ p3 = r5 + if (!p3.new) r17 = memub(r21+r31<<#3) } +# CHECK: f1 db 35 41 +if (p3) r17 = memub(r21 + #31) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 db 35 43 +{ p3 = r5 + if (p3.new) r17 = memub(r21 + #31) } +# CHECK: f1 db 35 45 +if (!p3) r17 = memub(r21 + #31) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 db 35 47 +{ p3 = r5 + if (!p3.new) r17 = memub(r21 + #31) } +# CHECK: b1 e6 35 9b +if (p3) r17 = memub(r21++#5) +# CHECK: b1 ee 35 9b +if (!p3) r17 = memub(r21++#5) +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 f6 35 9b +{ p3 = r5 + if (p3.new) r17 = memub(r21++#5) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 fe 35 9b +{ p3 = r5 + if (!p3.new) r17 = memub(r21++#5) } + +# Load unsigned halfword +# CHECK: 91 ff 75 3a +r17 = memuh(r21 + r31<<#3) +# CHECK: b1 c2 60 49 +r17 = memuh(#42) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 51 c5 60 49 +r17 = memuh(##42) +# CHECK: b1 c2 75 91 +r17 = memuh(r21 + #42) +# CHECK: b1 e0 75 99 +r17 = memuh(r21 ++ #10:circ(m1)) +# CHECK: 11 e2 75 99 +r17 = memuh(r21 ++ I:circ(m1)) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 71 d7 75 9b +r17 = memuh(r21 = ##31) +# CHECK: b1 c0 75 9b +r17 = memuh(r21++#10) +# CHECK: 11 e0 75 9d +r17 = memuh(r21++m1) +# CHECK: 11 e0 75 9f +r17 = memuh(r21 ++ m1:brev) + +# Load unsigned halfword conditionally +# CHECK: f1 ff 75 30 +if (p3) r17 = memuh(r21+r31<<#3) +# CHECK: f1 ff 75 31 +if (!p3) r17 = memuh(r21+r31<<#3) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 75 32 +{ p3 = r5 + if (p3.new) r17 = memuh(r21+r31<<#3) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 75 33 +{ p3 = r5 + if (!p3.new) r17 = memuh(r21+r31<<#3) } +# CHECK: b1 da 75 41 +if (p3) r17 = memuh(r21 + #42) +# CHECK: b1 da 75 45 +if (!p3) r17 = memuh(r21 + #42) +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 da 75 43 +{ p3 = r5 + if (p3.new) r17 = memuh(r21 + #42) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 da 75 47 +{ p3 = r5 + if (!p3.new) r17 = memuh(r21 + #42) } +# CHECK: b1 e6 75 9b +if (p3) r17 = memuh(r21++#10) +# CHECK: b1 ee 75 9b +if (!p3) r17 = memuh(r21++#10) +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 f6 75 9b +{ p3 = r5 + if (p3.new) r17 = memuh(r21++#10) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 fe 75 9b +{ p3 = r5 + if (!p3.new) r17 = memuh(r21++#10) } + +# Load word +# CHECK: 91 ff 95 3a +r17 = memw(r21 + r31<<#3) +# CHECK: b1 c2 80 49 +r17 = memw(#84) +# CHECK: 01 40 00 00 +# CHECK-NEXT: 91 c2 80 49 +r17 = memw(##84) +# CHECK: b1 c2 95 91 +r17 = memw(r21 + #84) +# CHECK: b1 e0 95 99 +r17 = memw(r21 ++ #20:circ(m1)) +# CHECK: 11 e2 95 99 +r17 = memw(r21 ++ I:circ(m1)) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 71 d7 95 9b +r17 = memw(r21 = ##31) +# CHECK: b1 c0 95 9b +r17 = memw(r21++#20) +# CHECK: 11 e0 95 9d +r17 = memw(r21++m1) +# CHECK: 11 e0 95 9f +r17 = memw(r21 ++ m1:brev) + +# Load word conditionally +# CHECK: f1 ff 95 30 +if (p3) r17 = memw(r21+r31<<#3) +# CHECK: f1 ff 95 31 +if (!p3) r17 = memw(r21+r31<<#3) +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 95 32 +{ p3 = r5 + if (p3.new) r17 = memw(r21+r31<<#3) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f1 ff 95 33 +{ p3 = r5 + if (!p3.new) r17 = memw(r21+r31<<#3) } +# CHECK: b1 da 95 41 +if (p3) r17 = memw(r21 + #84) +# CHECK: b1 da 95 45 +if (!p3) r17 = memw(r21 + #84) +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 da 95 43 +{ p3 = r5 + if (p3.new) r17 = memw(r21 + #84) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 da 95 47 +{ p3 = r5 + if (!p3.new) r17 = memw(r21 + #84) } +# CHECK: b1 e6 95 9b +if (p3) r17 = memw(r21++#20) +# CHECK: b1 ee 95 9b +if (!p3) r17 = memw(r21++#20) +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 f6 95 9b +{ p3 = r5 + if (p3.new) r17 = memw(r21++#20) } +# CHECK: 03 40 45 85 +# CHECK-NEXT: b1 fe 95 9b +{ p3 = r5 + if (!p3.new) r17 = memw(r21++#20) } + +# Deallocate stack frame +# CHECK: 1e c0 1e 90 +deallocframe + +# Deallocate stack frame and return +# CHECK: 1e c0 1e 96 +dealloc_return +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1e cb 1e 96 +{ p3 = r5 + if (p3.new) dealloc_return:nt } +# CHECK: 1e d3 1e 96 +if (p3) dealloc_return +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1e db 1e 96 +{ p3 = r5 + if (p3.new) dealloc_return:t } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1e eb 1e 96 +{ p3 = r5 + if (!p3.new) dealloc_return:nt } +# CHECK: 1e f3 1e 96 +if (!p3) dealloc_return +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1e fb 1e 96 +{ p3 = r5 + if (!p3.new) dealloc_return:t } + +# Load and unpack bytes to halfwords +# CHECK: f1 c3 35 90 +r17 = membh(r21 + #62) +# CHECK: f1 c3 75 90 +r17 = memubh(r21 + #62) +# CHECK: f0 c3 b5 90 +r17:16 = memubh(r21 + #124) +# CHECK: f0 c3 f5 90 +r17:16 = membh(r21 + #124) +# CHECK: b1 e0 35 98 +r17 = membh(r21 ++ #10:circ(m1)) +# CHECK: 11 e2 35 98 +r17 = membh(r21 ++ I:circ(m1)) +# CHECK: b1 e0 75 98 +r17 = memubh(r21 ++ #10:circ(m1)) +# CHECK: 11 e2 75 98 +r17 = memubh(r21 ++ I:circ(m1)) +# CHECK: b0 e0 f5 98 +r17:16 = membh(r21 ++ #20:circ(m1)) +# CHECK: 10 e2 f5 98 +r17:16 = membh(r21 ++ I:circ(m1)) +# CHECK: b0 e0 b5 98 +r17:16 = memubh(r21 ++ #20:circ(m1)) +# CHECK: 10 e2 b5 98 +r17:16 = memubh(r21 ++ I:circ(m1)) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 71 d7 35 9a +r17 = membh(r21 = ##31) +# CHECK: b1 c0 35 9a +r17 = membh(r21++#10) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 71 d7 75 9a +r17 = memubh(r21 = ##31) +# CHECK: b1 c0 75 9a +r17 = memubh(r21++#10) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 70 d7 b5 9a +r17:16 = memubh(r21 = ##31) +# CHECK: b0 c0 b5 9a +r17:16 = memubh(r21++#20) +# CHECK: 00 40 00 00 +# CHECK-NEXT: 70 d7 f5 9a +r17:16 = membh(r21 = ##31) +# CHECK: b0 c0 f5 9a +r17:16 = membh(r21++#20) +# CHECK: 00 40 00 00 +# CHECK-NEXT: f1 f7 35 9c +r17 = membh(r21<<#3 + ##31) +# CHECK: 11 e0 35 9c +r17 = membh(r21++m1) +# CHECK: 00 40 00 00 +# CHECK-NEXT: f1 f7 75 9c +r17 = memubh(r21<<#3 + ##31) +# CHECK: 11 e0 75 9c +r17 = memubh(r21++m1) +# CHECK: 00 40 00 00 +# CHECK-NEXT: f0 f7 f5 9c +r17:16 = membh(r21<<#3 + ##31) +# CHECK: 10 e0 f5 9c +r17:16 = membh(r21++m1) +# CHECK: 00 40 00 00 +# CHECK-NEXT: f0 f7 b5 9c +r17:16 = memubh(r21<<#3 + ##31) +# CHECK: 11 e0 35 9c +r17 = membh(r21++m1) +# CHECK: 11 e0 75 9c +r17 = memubh(r21++m1) +# CHECK: 10 e0 f5 9c +r17:16 = membh(r21++m1) +# CHECK: 10 e0 b5 9c +r17:16 = memubh(r21++m1) +# CHECK: 11 e0 35 9e +r17 = membh(r21 ++ m1:brev) +# CHECK: 11 e0 75 9e +r17 = memubh(r21 ++ m1:brev) +# CHECK: 10 e0 b5 9e +r17:16 = memubh(r21 ++ m1:brev) +# CHECK: 10 e0 f5 9e +r17:16 = membh(r21 ++ m1:brev) diff --git a/test/MC/Hexagon/instructions/memop.s b/test/MC/Hexagon/instructions/memop.s new file mode 100644 index 00000000000..1aac69056b1 --- /dev/null +++ b/test/MC/Hexagon/instructions/memop.s @@ -0,0 +1,56 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.6 MEMOP + +# Operation on memory byte +# CHECK: 95 d9 11 3e +memb(r17+#51) += r21 +# CHECK: b5 d9 11 3e +memb(r17+#51) -= r21 +# CHECK: d5 d9 11 3e +memb(r17+#51) &= r21 +# CHECK: f5 d9 11 3e +memb(r17+#51) |= r21 +# CHECK: 95 d9 11 3f +memb(r17+#51) += #21 +# CHECK: b5 d9 11 3f +memb(r17+#51) -= #21 +# CHECK: d5 d9 11 3f +memb(r17+#51) = clrbit(#21) +# CHECK: f5 d9 11 3f +memb(r17+#51) = setbit(#21) + +# Operation on memory halfword +# CHECK: 95 d9 31 3e +memh(r17+#102) += r21 +# CHECK: b5 d9 31 3e +memh(r17+#102) -= r21 +# CHECK: d5 d9 31 3e +memh(r17+#102) &= r21 +# CHECK: f5 d9 31 3e +memh(r17+#102) |= r21 +# CHECK: 95 d9 31 3f +memh(r17+#102) += #21 +# CHECK: b5 d9 31 3f +memh(r17+#102) -= #21 +# CHECK: d5 d9 31 3f +memh(r17+#102) = clrbit(#21) +# CHECK: f5 d9 31 3f +memh(r17+#102) = setbit(#21) + +# Operation on memory word +# CHECK: 95 d9 51 3e +memw(r17+#204) += r21 +# CHECK: b5 d9 51 3e +memw(r17+#204) -= r21 +# CHECK: d5 d9 51 3e +memw(r17+#204) &= r21 +# CHECK: f5 d9 51 3e +memw(r17+#204) |= r21 +# CHECK: 95 d9 51 3f +memw(r17+#204) += #21 +# CHECK: b5 d9 51 3f +memw(r17+#204) -= #21 +# CHECK: d5 d9 51 3f +memw(r17+#204) = clrbit(#21) +# CHECK: f5 d9 51 3f +memw(r17+#204) = setbit(#21) diff --git a/test/MC/Hexagon/instructions/nv_j.s b/test/MC/Hexagon/instructions/nv_j.s new file mode 100644 index 00000000000..5bc75c5a964 --- /dev/null +++ b/test/MC/Hexagon/instructions/nv_j.s @@ -0,0 +1,180 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.7.1 NV/J + +# Jump to address conditioned on new register value +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 02 20 +{ r17 = r17 + if (cmp.eq(r17.new, r21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 02 20 +{ r17 = r17 + if (cmp.eq(r17.new, r21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 42 20 +{ r17 = r17 + if (!cmp.eq(r17.new, r21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 42 20 +{ r17 = r17 + if (!cmp.eq(r17.new, r21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 82 20 +{ r17 = r17 + if (cmp.gt(r17.new, r21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 82 20 +{ r17 = r17 + if (cmp.gt(r17.new, r21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 c2 20 +{ r17 = r17 + if (!cmp.gt(r17.new, r21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 c2 20 +{ r17 = r17 + if (!cmp.gt(r17.new, r21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 02 21 +{ r17 = r17 + if (cmp.gtu(r17.new, r21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 02 21 +{ r17 = r17 + if (cmp.gtu(r17.new, r21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 42 21 +{ r17 = r17 + if (!cmp.gtu(r17.new, r21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 42 21 +{ r17 = r17 + if (!cmp.gtu(r17.new, r21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 82 21 +{ r17 = r17 + if (cmp.gt(r21, r17.new)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 82 21 +{ r17 = r17 + if (cmp.gt(r21, r17.new)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 c2 21 +{ r17 = r17 + if (!cmp.gt(r21, r17.new)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 c2 21 +{ r17 = r17 + if (!cmp.gt(r21, r17.new)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 02 22 +{ r17 = r17 + if (cmp.gtu(r21, r17.new)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 02 22 +{ r17 = r17 + if (cmp.gtu(r21, r17.new)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 42 22 +{ r17 = r17 + if (!cmp.gtu(r21, r17.new)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 42 22 +{ r17 = r17 + if (!cmp.gtu(r21, r17.new)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 02 24 +{ r17 = r17 + if (cmp.eq(r17.new, #21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 02 24 +{ r17 = r17 + if (cmp.eq(r17.new, #21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 42 24 +{ r17 = r17 + if (!cmp.eq(r17.new, #21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 42 24 +{ r17 = r17 + if (!cmp.eq(r17.new, #21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 82 24 +{ r17 = r17 + if (cmp.gt(r17.new, #21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 82 24 +{ r17 = r17 + if (cmp.gt(r17.new, #21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 c2 24 +{ r17 = r17 + if (!cmp.gt(r17.new, #21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 c2 24 +{ r17 = r17 + if (!cmp.gt(r17.new, #21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 02 25 +{ r17 = r17 + if (cmp.gtu(r17.new, #21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 02 25 +{ r17 = r17 + if (cmp.gtu(r17.new, #21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 d5 42 25 +{ r17 = r17 + if (!cmp.gtu(r17.new, #21)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 f5 42 25 +{ r17 = r17 + if (!cmp.gtu(r17.new, #21)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 c0 82 25 +{ r17 = r17 + if (tstbit(r17.new, #0)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 e0 82 25 +{ r17 = r17 + if (tstbit(r17.new, #0)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 c0 c2 25 +{ r17 = r17 + if (!tstbit(r17.new, #0)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 e0 c2 25 +{ r17 = r17 + if (!tstbit(r17.new, #0)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 c0 02 26 +{ r17 = r17 + if (cmp.eq(r17.new, #-1)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 e0 02 26 +{ r17 = r17 + if (cmp.eq(r17.new, #-1)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 c0 42 26 +{ r17 = r17 + if (!cmp.eq(r17.new, #-1)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 e0 42 26 +{ r17 = r17 + if (!cmp.eq(r17.new, #-1)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 c0 82 26 +{ r17 = r17 + if (cmp.gt(r17.new, #-1)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 e0 82 26 +{ r17 = r17 + if (cmp.gt(r17.new, #-1)) jump:t 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 c0 c2 26 +{ r17 = r17 + if (!cmp.gt(r17.new, #-1)) jump:nt 0x0 } +# CHECK: 11 40 71 70 +# CHECK-NEXT: 00 e0 c2 26 +{ r17 = r17 + if (!cmp.gt(r17.new, #-1)) jump:t 0x0 } diff --git a/test/MC/Hexagon/instructions/nv_st.s b/test/MC/Hexagon/instructions/nv_st.s new file mode 100644 index 00000000000..4ff490024a8 --- /dev/null +++ b/test/MC/Hexagon/instructions/nv_st.s @@ -0,0 +1,290 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.7.2 NV/ST + +# Store new-value byte +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 82 f5 b1 3b +{ r31 = r31 + memb(r17 + r21<<#3) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 11 c2 a0 48 +{ r31 = r31 + memb(#17) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 15 c2 b1 a1 +{ r31 = r31 + memb(r17+#21) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 02 e2 b1 a9 +{ r31 = r31 + memb(r17 ++ I:circ(m1)) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 28 e2 b1 a9 +{ r31 = r31 + memb(r17 ++ #5:circ(m1)) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 28 c2 b1 ab +{ r31 = r31 + memb(r17++#5) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 00 e2 b1 ad +{ r31 = r31 + memb(r17++m1) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 00 e2 b1 af +{ r31 = r31 + memb(r17 ++ m1:brev) = r31.new } + +# Store new-value byte conditionally +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: e2 f5 b1 34 +{ r31 = r31 + if (p3) memb(r17+r21<<#3) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: e2 f5 b1 35 +{ r31 = r31 + if (!p3) memb(r17+r21<<#3) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: e2 f5 b1 36 +{ p3 = r5 + r31 = r31 + if (p3.new) memb(r17+r21<<#3) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: e2 f5 b1 37 +{ p3 = r5 + r31 = r31 + if (!p3.new) memb(r17+r21<<#3) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: ab c2 b1 40 +{ r31 = r31 + if (p3) memb(r17+#21) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: ab c2 b1 44 +{ r31 = r31 + if (!p3) memb(r17+#21) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ab c2 b1 42 +{ p3 = r5 + r31 = r31 + if (p3.new) memb(r17+#21) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ab c2 b1 46 +{ p3 = r5 + r31 = r31 + if (!p3.new) memb(r17+#21) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 2b e2 b1 ab +{ r31 = r31 + if (p3) memb(r17++#5) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 2f e2 b1 ab +{ r31 = r31 + if (!p3) memb(r17++#5) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ab e2 b1 ab +{ p3 = r5 + r31 = r31 + if (p3.new) memb(r17++#5) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: af e2 b1 ab +{ p3 = r5 + r31 = r31 + if (!p3.new) memb(r17++#5) = r31.new } + +# Store new-value halfword +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 8a f5 b1 3b +{ r31 = r31 + memh(r17 + r21<<#3) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 15 ca a0 48 +{ r31 = r31 + memh(#42) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 15 ca b1 a1 +{ r31 = r31 + memh(r17+#42) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 02 ea b1 a9 +{ r31 = r31 + memh(r17 ++ I:circ(m1)) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 28 ea b1 a9 +{ r31 = r31 + memh(r17 ++ #10:circ(m1)) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 28 ca b1 ab +{ r31 = r31 + memh(r17++#10) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 00 ea b1 ad +{ r31 = r31 + memh(r17++m1) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 00 ea b1 af +{ r31 = r31 + memh(r17 ++ m1:brev) = r31.new } + +# Store new-value halfword conditionally +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: ea f5 b1 34 +{ r31 = r31 + if (p3) memh(r17+r21<<#3) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: ea f5 b1 35 +{ r31 = r31 + if (!p3) memh(r17+r21<<#3) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ea f5 b1 36 +{ p3 = r5 + r31 = r31 + if (p3.new) memh(r17+r21<<#3) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ea f5 b1 37 +{ p3 = r5 + r31 = r31 + if (!p3.new) memh(r17+r21<<#3) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: ab ca b1 40 +{ r31 = r31 + if (p3) memh(r17+#42) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: ab ca b1 44 +{ r31 = r31 + if (!p3) memh(r17+#42) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ab ca b1 42 +{ p3 = r5 + r31 = r31 + if (p3.new) memh(r17+#42) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ab ca b1 46 +{ p3 = r5 + r31 = r31 + if (!p3.new) memh(r17+#42) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 2b ea b1 ab +{ r31 = r31 + if (p3) memh(r17++#10) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 2f ea b1 ab +{ r31 = r31 + if (!p3) memh(r17++#10) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ab ea b1 ab +{ p3 = r5 + r31 = r31 + if (p3.new) memh(r17++#10) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: af ea b1 ab +{ p3 = r5 + r31 = r31 + if (!p3.new) memh(r17++#10) = r31.new } + +# Store new-value word +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 92 f5 b1 3b +{ r31 = r31 + memw(r17 + r21<<#3) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 15 d2 a0 48 +{ r31 = r31 + memw(#84) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 15 d2 b1 a1 +{ r31 = r31 + memw(r17+#84) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 02 f2 b1 a9 +{ r31 = r31 + memw(r17 ++ I:circ(m1)) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 28 f2 b1 a9 +{ r31 = r31 + memw(r17 ++ #20:circ(m1)) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 28 d2 b1 ab +{ r31 = r31 + memw(r17++#20) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 00 f2 b1 ad +{ r31 = r31 + memw(r17++m1) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 00 f2 b1 af +{ r31 = r31 + memw(r17 ++ m1:brev) = r31.new } + +# Store new-value word conditionally +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: f2 f5 b1 34 +{ r31 = r31 + if (p3) memw(r17+r21<<#3) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: f2 f5 b1 35 +{ r31 = r31 + if (!p3) memw(r17+r21<<#3) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: f2 f5 b1 36 +{ p3 = r5 + r31 = r31 + if (p3.new) memw(r17+r21<<#3) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: f2 f5 b1 37 +{ p3 = r5 + r31 = r31 + if (!p3.new) memw(r17+r21<<#3) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: ab d2 b1 40 +{ r31 = r31 + if (p3) memw(r17+#84) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: ab d2 b1 44 +{ r31 = r31 + if (!p3) memw(r17+#84) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ab d2 b1 42 +{ p3 = r5 + r31 = r31 + if (p3.new) memw(r17+#84) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ab d2 b1 46 +{ p3 = r5 + r31 = r31 + if (!p3.new) memw(r17+#84) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 2b f2 b1 ab +{ r31 = r31 + if (p3) memw(r17++#20) = r31.new } +# CHECK: 1f 40 7f 70 +# CHECK-NEXT: 2f f2 b1 ab +{ r31 = r31 + if (!p3) memw(r17++#20) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: ab f2 b1 ab +{ p3 = r5 + r31 = r31 + if (p3.new) memw(r17++#20) = r31.new } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 1f 40 7f 70 +# CHECK-NEXT: af f2 b1 ab +{ p3 = r5 + r31 = r31 + if (!p3.new) memw(r17++#20) = r31.new } diff --git a/test/MC/Hexagon/instructions/st.s b/test/MC/Hexagon/instructions/st.s new file mode 100644 index 00000000000..38822a62043 --- /dev/null +++ b/test/MC/Hexagon/instructions/st.s @@ -0,0 +1,435 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.8 ST +# XFAIL: * + +# Store doubleword +# CHECK: 9e f5 d1 3b +memd(r17 + r21<<#3) = r31:30 +# CHECK: 28 d4 c0 48 +memd(#320) = r21:20 +# CHECK: 02 40 00 00 +# CHECK-NEXT: 28 d4 c0 48 +memd(##168) = r21:20 +memd(r17+#168) = r21:20 +# CHECK: 02 f4 d1 a9 +memd(r17 ++ I:circ(m1)) = r21:20 +# CHECK: 28 f4 d1 a9 +memd(r17 ++ #40:circ(m1)) = r21:20 +# CHECK: 28 d4 d1 ab +memd(r17++#40) = r21:20 +# CHECK: 00 40 00 00 +# CHECK-NEXT: d5 fe d1 ad +memd(r17<<#3 + ##21) = r31:30 +memd(r17++m1) = r21:20 +# CHECK: 00 f4 d1 af +memd(r17 ++ m1:brev) = r21:20 + +# Store doubleword conditionally +# CHECK: fe f5 d1 34 +if (p3) memd(r17+r21<<#3) = r31:30 +# CHECK: fe f5 d1 35 +if (!p3) memd(r17+r21<<#3) = r31:30 +# CHECK: 03 40 45 85 +# CHECK-NEXT: fe f5 d1 36 +{ p3 = r5 + if (p3.new) memd(r17+r21<<#3) = r31:30 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: fe f5 d1 37 +{ p3 = r5 + if (!p3.new) memd(r17+r21<<#3) = r31:30 } +# CHECK: ab de d1 40 +if (p3) memd(r17+#168) = r31:30 +# CHECK: ab de d1 44 +if (!p3) memd(r17+#168) = r31:30 +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab de d1 42 +{ p3 = r5 + if (p3.new) memd(r17+#168) = r31:30 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab de d1 46 +{ p3 = r5 + if (!p3.new) memd(r17+#168) = r31:30 } +# CHECK: 2b f4 d1 ab +if (p3) memd(r17++#40) = r21:20 +# CHECK: 2f f4 d1 ab +if (!p3) memd(r17++#40) = r21:20 +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab f4 d1 ab +{ p3 = r5 + if (p3.new) memd(r17++#40) = r21:20 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: af f4 d1 ab +{ p3 = r5 + if (!p3.new) memd(r17++#40) = r21:20 } +# CHECK: 02 40 00 00 +# CHECK-NEXT: c3 d4 c2 af +if (p3) memd(##168) = r21:20 +# CHECK: 02 40 00 00 +# CHECK-NEXT: c7 d4 c2 af +if (!p3) memd(##168) = r21:20 +# CHECK: 03 40 45 85 +# CHECK-NEXT: 02 40 00 00 +# CHECK-NEXT: c3 f4 c2 af +{ p3 = r5 + if (p3.new) memd(##168) = r21:20 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 02 40 00 00 +# CHECK-NEXT: c7 f4 c2 af +{ p3 = r5 + if (!p3.new) memd(##168) = r21:20 } + +# Store byte +# CHECK: 9f f5 11 3b +memb(r17 + r21<<#3) = r31 +# CHECK: 9f ca 11 3c +memb(r17+#21)=#31 +# CHECK: 15 d5 00 48 +memb(#21) = r21 +# CHECK: 00 40 00 00 +# CHECK-NEXT: 15 d5 00 48 +memb(##21) = r21 +# CHECK: 15 d5 11 a1 +memb(r17+#21) = r21 +# CHECK: 02 f5 11 a9 +memb(r17 ++ I:circ(m1)) = r21 +# CHECK: 28 f5 11 a9 +memb(r17 ++ #5:circ(m1)) = r21 +# CHECK: 28 d5 11 ab +memb(r17++#5) = r21 +# CHECK: 00 40 00 00 +# CHECK-NEXT: d5 ff 11 ad +memb(r17<<#3 + ##21) = r31 +# CHECK: 00 f5 11 ad +memb(r17++m1) = r21 +# CHECK: 00 f5 11 af +memb(r17 ++ m1:brev) = r21 + +# Store byte conditionally +# CHECK: ff f5 11 34 +if (p3) memb(r17+r21<<#3) = r31 +# CHECK: ff f5 11 35 +if (!p3) memb(r17+r21<<#3) = r31 +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff f5 11 36 +{ p3 = r5 + if (p3.new) memb(r17+r21<<#3) = r31 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff f5 11 37 +{ p3 = r5 + if (!p3.new) memb(r17+r21<<#3) = r31 } +# CHECK: ff ca 11 38 +if (p3) memb(r17+#21)=#31 +# CHECK: ff ca 91 38 +if (!p3) memb(r17+#21)=#31 +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff ca 11 39 +{ p3 = r5 + if (p3.new) memb(r17+#21)=#31 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff ca 91 39 +{ p3 = r5 + if (!p3.new) memb(r17+#21)=#31 } +# CHECK: ab df 11 40 +if (p3) memb(r17+#21) = r31 +# CHECK: ab df 11 44 +if (!p3) memb(r17+#21) = r31 +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab df 11 42 +{ p3 = r5 + if (p3.new) memb(r17+#21) = r31 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab df 11 46 +{ p3 = r5 + if (!p3.new) memb(r17+#21) = r31 } +# CHECK: 2b f5 11 ab +if (p3) memb(r17++#5) = r21 +# CHECK: 2f f5 11 ab +if (!p3) memb(r17++#5) = r21 +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab f5 11 ab +{ p3 = r5 + if (p3.new) memb(r17++#5) = r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: af f5 11 ab +{ p3 = r5 + if (!p3.new) memb(r17++#5) = r21 } +# CHECK: 00 40 00 00 +# CHECK-NEXT: ab d5 01 af +if (p3) memb(##21) = r21 +# CHECK: 00 40 00 00 +# CHECK-NEXT: af d5 01 af +if (!p3) memb(##21) = r21 +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 40 00 00 +# CHECK-NEXT: ab f5 01 af +{ p3 = r5 + if (p3.new) memb(##21) = r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 40 00 00 +# CHECK-NEXT: af f5 01 af +{ p3 = r5 + if (!p3.new) memb(##21) = r21 } + +# Store halfword +# CHECK: 9f f5 51 3b +memh(r17 + r21<<#3) = r31 +# CHECK: 9f f5 71 3b +memh(r17 + r21<<#3) = r31.h +# CHECK: 95 cf 31 3c +memh(r17+#62)=#21 +# CHECK: 00 40 00 00 +# CHECK-NEXT: 2a d5 40 48 +memh(##42) = r21 +# CHECK: 00 40 00 00 +# CHECK-NEXT: 2a d5 60 48 +memh(##42) = r21.h +# CHECK: 2a d5 40 48 +memh(#84) = r21 +# CHECK: 2a d5 60 48 +memh(#84) = r21.h +# CHECK: 15 df 51 a1 +memh(r17+#42) = r31 +# CHECK: 15 df 71 a1 +memh(r17+#42) = r31.h +# CHECK: 02 f5 51 a9 +memh(r17 ++ I:circ(m1)) = r21 +# CHECK: 28 f5 51 a9 +memh(r17 ++ #10:circ(m1)) = r21 +# CHECK: 02 f5 71 a9 +memh(r17 ++ I:circ(m1)) = r21.h +# CHECK: 28 f5 71 a9 +memh(r17 ++ #10:circ(m1)) = r21.h +# CHECK: 28 d5 51 ab +memh(r17++#10) = r21 +# CHECK: 00 40 00 00 +# CHECK-NEXT: d5 ff 51 ad +memh(r17<<#3 + ##21) = r31 +# CHECK: 28 d5 71 ab +memh(r17++#10) = r21.h +# CHECK: 00 40 00 00 +# CHECK-NEXT: d5 ff 71 ad +memh(r17<<#3 + ##21) = r31.h +# CHECK: 00 f5 51 ad +memh(r17++m1) = r21 +# CHECK: 00 f5 71 ad +memh(r17++m1) = r21.h +# CHECK: 00 f5 51 af +memh(r17 ++ m1:brev) = r21 +# CHECK: 00 f5 71 af +memh(r17 ++ m1:brev) = r21.h + +# Store halfword conditionally +# CHECK: ff f5 51 34 +if (p3) memh(r17+r21<<#3) = r31 +# CHECK: ff f5 71 34 +if (p3) memh(r17+r21<<#3) = r31.h +# CHECK: ff f5 51 35 +if (!p3) memh(r17+r21<<#3) = r31 +# CHECK: ff f5 71 35 +if (!p3) memh(r17+r21<<#3) = r31.h +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff f5 51 36 +{ p3 = r5 + if (p3.new) memh(r17+r21<<#3) = r31 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff f5 71 36 +{ p3 = r5 + if (p3.new) memh(r17+r21<<#3) = r31.h } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff f5 51 37 +{ p3 = r5 + if (!p3.new) memh(r17+r21<<#3) = r31 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff f5 71 37 +{ p3 = r5 + if (!p3.new) memh(r17+r21<<#3) = r31.h } +# CHECK: f5 cf 31 38 +if (p3) memh(r17+#62)=#21 +# CHECK: f5 cf b1 38 +if (!p3) memh(r17+#62)=#21 +# CHECK: 03 40 45 85 +# CHECK-NEXT: f5 cf 31 39 +{ p3 = r5 + if (p3.new) memh(r17+#62)=#21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: f5 cf b1 39 +{ p3 = r5 + if (!p3.new) memh(r17+#62)=#21 } +# CHECK: fb d5 51 40 +if (p3) memh(r17+#62) = r21 +# CHECK: fb d5 71 40 +if (p3) memh(r17+#62) = r21.h +# CHECK: fb d5 51 44 +if (!p3) memh(r17+#62) = r21 +# CHECK: fb d5 71 44 +if (!p3) memh(r17+#62) = r21.h +# CHECK: 03 40 45 85 +# CHECK-NEXT: fb d5 51 42 +{ p3 = r5 + if (p3.new) memh(r17+#62) = r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: fb d5 71 42 +{ p3 = r5 + if (p3.new) memh(r17+#62) = r21.h } +# CHECK: 03 40 45 85 +# CHECK-NEXT: fb d5 51 46 +{ p3 = r5 + if (!p3.new) memh(r17+#62) = r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: fb d5 71 46 +{ p3 = r5 + if (!p3.new) memh(r17+#62) = r21.h } +# CHECK: 2b f5 51 ab +if (p3) memh(r17++#10) = r21 +# CHECK: 2f f5 51 ab +if (!p3) memh(r17++#10) = r21 +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab f5 51 ab +{ p3 = r5 + if (p3.new) memh(r17++#10) = r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: af f5 51 ab +{ p3 = r5 + if (!p3.new) memh(r17++#10) = r21 } +# CHECK: 2b f5 71 ab +if (p3) memh(r17++#10) = r21.h +# CHECK: 2f f5 71 ab +if (!p3) memh(r17++#10) = r21.h +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab f5 71 ab +{ p3 = r5 + if (p3.new) memh(r17++#10) = r21.h } +# CHECK: 03 40 45 85 +# CHECK-NEXT: af f5 71 ab +{ p3 = r5 + if (!p3.new) memh(r17++#10) = r21.h } +# CHECK: 00 40 00 00 +# CHECK-NEXT: d3 d5 42 af +if (p3) memh(##42) = r21 +# CHECK: 00 40 00 00 +# CHECK-NEXT: d3 d5 62 af +if (p3) memh(##42) = r21.h +# CHECK: 00 40 00 00 +# CHECK-NEXT: d7 d5 42 af +if (!p3) memh(##42) = r21 +# CHECK: 00 40 00 00 +# CHECK-NEXT: d7 d5 62 af +if (!p3) memh(##42) = r21.h +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 40 00 00 +# CHECK-NEXT: d3 f5 42 af +{ p3 = r5 + if (p3.new) memh(##42) = r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 40 00 00 +# CHECK-NEXT: d3 f5 62 af +{ p3 = r5 + if (p3.new) memh(##42) = r21.h } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 40 00 00 +# CHECK-NEXT: d7 f5 42 af +{ p3 = r5 + if (!p3.new) memh(##42) = r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 00 40 00 00 +# CHECK-NEXT: d7 f5 62 af +{ p3 = r5 + if (!p3.new) memh(##42) = r21.h } + +# Store word +# CHECK: 9f f5 91 3b +memw(r17 + r21<<#3) = r31 +# CHECK: 9f ca 51 3c +memw(r17+#84)=#31 +# CHECK: 15 df 80 48 +memw(#84) = r31 +# CHECK: 01 40 00 00 +# CHECK-NEXT: 14 d5 80 48 +memw(##84) = r21 +# CHECK: 9f ca 51 3c +memw(r17+#84)=#31 +# CHECK: 15 df 91 a1 +memw(r17+#84) = r31 +# CHECK: 02 f5 91 a9 +memw(r17 ++ I:circ(m1)) = r21 +# CHECK: 28 f5 91 a9 +memw(r17 ++ #20:circ(m1)) = r21 +# CHECK: 28 d5 91 ab +memw(r17++#20) = r21 +# CHECK: 00 40 00 00 +# CHECK-NEXT: d5 ff 91 ad +memw(r17<<#3 + ##21) = r31 +# CHECK: 00 f5 91 ad +memw(r17++m1) = r21 +# CHECK: 00 f5 91 af +memw(r17 ++ m1:brev) = r21 + +# Store word conditionally +# CHECK: ff f5 91 34 +if (p3) memw(r17+r21<<#3) = r31 +# CHECK: ff f5 91 35 +if (!p3) memw(r17+r21<<#3) = r31 +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff f5 91 36 +{ p3 = r5 + if (p3.new) memw(r17+r21<<#3) = r31 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff f5 91 37 +{ p3 = r5 + if (!p3.new) memw(r17+r21<<#3) = r31 } +# CHECK: ff ca 51 38 +if (p3) memw(r17+#84)=#31 +# CHECK: ff ca d1 38 +if (!p3) memw(r17+#84)=#31 +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff ca 51 39 +{ p3 = r5 + if (p3.new) memw(r17+#84)=#31 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ff ca d1 39 +{ p3 = r5 + if (!p3.new) memw(r17+#84)=#31 } +# CHECK: ab df 91 40 +if (p3) memw(r17+#84) = r31 +# CHECK: ab df 91 44 +if (!p3) memw(r17+#84) = r31 +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab df 91 42 +{ p3 = r5 + if (p3.new) memw(r17+#84) = r31 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab df 91 46 +{ p3 = r5 + if (!p3.new) memw(r17+#84) = r31 } +# CHECK: 2b f5 91 ab +if (p3) memw(r17++#20) = r21 +# CHECK: 2f f5 91 ab +if (!p3) memw(r17++#20) = r21 +# CHECK: 03 40 45 85 +# CHECK-NEXT: af f5 91 ab +{ p3 = r5 + if (!p3.new) memw(r17++#20) = r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: ab f5 91 ab +{ p3 = r5 + if (p3.new) memw(r17++#20) = r21 } +# CHECK: 01 40 00 00 +# CHECK-NEXT: a3 d5 81 af +if (p3) memw(##84) = r21 +# CHECK: 01 40 00 00 +# CHECK-NEXT: a7 d5 81 af +if (!p3) memw(##84) = r21 +# CHECK: 03 40 45 85 +# CHECK-NEXT: 01 40 00 00 +# CHECK-NEXT: a3 f5 81 af +{ p3 = r5 + if (p3.new) memw(##84) = r21 } +# CHECK: 03 40 45 85 +# CHECK-NEXT: 01 40 00 00 +# CHECK-NEXT: a7 f5 81 af +{ p3 = r5 + if (!p3.new) memw(##84) = r21 } + +# Allocate stack frame +# CHECK: 1f c0 9d a0 +allocframe(#248) diff --git a/test/MC/Hexagon/instructions/system_user.s b/test/MC/Hexagon/instructions/system_user.s new file mode 100644 index 00000000000..d52f8b41182 --- /dev/null +++ b/test/MC/Hexagon/instructions/system_user.s @@ -0,0 +1,26 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.9.1 SYSTEM/USER + +# Load locked +# CHECK: 11 c0 15 92 +r17 = memw_locked(r21) +# CHECK: 10 d0 15 92 +r17:16 = memd_locked(r21) + +# Store conditional +# CHECK: 03 d5 b1 a0 +memw_locked(r17, p3) = r21 +# CHECK: 03 d4 f1 a0 +memd_locked(r17, p3) = r21:20 + +# Memory barrier +# CHECK: 00 c0 00 a8 +barrier + +# Data cache prefetch +# CHECK: 15 c0 11 94 +dcfetch(r17 + #168) + +# Send value to ETM trace +# CHECK: 00 c0 51 62 +trace(r17) diff --git a/test/MC/Hexagon/instructions/xtype_alu.s b/test/MC/Hexagon/instructions/xtype_alu.s new file mode 100644 index 00000000000..b68175ed1e2 --- /dev/null +++ b/test/MC/Hexagon/instructions/xtype_alu.s @@ -0,0 +1,395 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.10.1 XTYPE/ALU + +# Absolute value doubleword +# CHECK: d0 c0 94 80 +r17:16 = abs(r21:20) +# CHECK: 91 c0 95 8c +r17 = abs(r21) +# CHECK: b1 c0 95 8c +r17 = abs(r21):sat + +# Add and accumulate +# CHECK: ff d1 35 db +r17 = add(r21, add(r31, #23)) +# CHECK: ff d1 b5 db +r17 = add(r21, sub(#23, r31)) +# CHECK: f1 c2 15 e2 +r17 += add(r21, #23) +# CHECK: f1 c2 95 e2 +r17 -= add(r21, #23) +# CHECK: 31 df 15 ef +r17 += add(r21, r31) +# CHECK: 31 df 95 ef +r17 -= add(r21, r31) + +# Add doublewords +# CHECK: f0 de 14 d3 +r17:16 = add(r21:20, r31:30) +# CHECK: b0 de 74 d3 +r17:16 = add(r21:20, r31:30):sat +# CHECK: d0 de 74 d3 +r17:16 = add(r21:20, r31:30):raw:lo +# CHECK: f0 de 74 d3 +r17:16 = add(r21:20, r31:30):raw:hi + +# Add halfword +# CHECK: 11 d5 1f d5 +r17 = add(r21.l, r31.l) +# CHECK: 51 d5 1f d5 +r17 = add(r21.l, r31.h) +# CHECK: 91 d5 1f d5 +r17 = add(r21.l, r31.l):sat +# CHECK: d1 d5 1f d5 +r17 = add(r21.l, r31.h):sat +# CHECK: 11 d5 5f d5 +r17 = add(r21.l, r31.l):<<16 +# CHECK: 31 d5 5f d5 +r17 = add(r21.l, r31.h):<<16 +# CHECK: 51 d5 5f d5 +r17 = add(r21.h, r31.l):<<16 +# CHECK: 71 d5 5f d5 +r17 = add(r21.h, r31.h):<<16 +# CHECK: 91 d5 5f d5 +r17 = add(r21.l, r31.l):sat:<<16 +# CHECK: b1 d5 5f d5 +r17 = add(r21.l, r31.h):sat:<<16 +# CHECK: d1 d5 5f d5 +r17 = add(r21.h, r31.l):sat:<<16 +# CHECK: f1 d5 5f d5 +r17 = add(r21.h, r31.h):sat:<<16 + +# Add or subtract doublewords with carry +# CHECK: 70 de d4 c2 +r17:16 = add(r21:20, r31:30, p3):carry +# CHECK: 70 de f4 c2 +r17:16 = sub(r21:20, r31:30, p3):carry + +# Logical doublewords +# CHECK: 90 c0 94 80 +r17:16 = not(r21:20) +# CHECK: 10 de f4 d3 +r17:16 = and(r21:20, r31:30) +# CHECK: 30 d4 fe d3 +r17:16 = and(r21:20, ~r31:30) +# CHECK: 50 de f4 d3 +r17:16 = or(r21:20, r31:30) +# CHECK: 70 d4 fe d3 +r17:16 = or(r21:20, ~r31:30) +# CHECK: 90 de f4 d3 +r17:16 = xor(r21:20, r31:30) + +# Logical-logical doublewords +# CHECK: 10 de 94 ca +r17:16 ^= xor(r21:20, r31:30) + +# Logical-logical words +# CHECK: f1 c3 15 da +r17 |= and(r21, #31) +# CHECK: f5 c3 51 da +r17 = or(r21, and(r17, #31)) +# CHECK: f1 c3 95 da +r17 |= or(r21, #31) +# CHECK: 11 df 35 ef +r17 |= and(r21, ~r31) +# CHECK: 31 df 35 ef +r17 &= and(r21, ~r31) +# CHECK: 51 df 35 ef +r17 ^= and(r21, ~r31) +# CHECK: 11 df 55 ef +r17 &= and(r21, r31) +# CHECK: 31 df 55 ef +r17 &= or(r21, r31) +# CHECK: 51 df 55 ef +r17 &= xor(r21, r31) +# CHECK: 71 df 55 ef +r17 |= and(r21, r31) +# CHECK: 71 df 95 ef +r17 ^= xor(r21, r31) +# CHECK: 11 df d5 ef +r17 |= or(r21, r31) +# CHECK: 31 df d5 ef +r17 |= xor(r21, r31) +# CHECK: 51 df d5 ef +r17 ^= and(r21, r31) +# CHECK: 71 df d5 ef +r17 ^= or(r21, r31) + +# Maximum words +# CHECK: 11 df d5 d5 +r17 = max(r21, r31) +# CHECK: 91 df d5 d5 +r17 = maxu(r21, r31) + +# Maximum doublewords +# CHECK: 90 de d4 d3 +r17:16 = max(r21:20, r31:30) +# CHECK: b0 de d4 d3 +r17:16 = maxu(r21:20, r31:30) + +# Minimum words +# CHECK: 11 d5 bf d5 +r17 = min(r21, r31) +# CHECK: 91 d5 bf d5 +r17 = minu(r21, r31) + +# Minimum doublewords +# CHECK: d0 d4 be d3 +r17:16 = min(r21:20, r31:30) +# CHECK: f0 d4 be d3 +r17:16 = minu(r21:20, r31:30) + +# Module wrap +# CHECK: f1 df f5 d3 +r17 = modwrap(r21, r31) + +# Negate +# CHECK: b0 c0 94 80 +r17:16 = neg(r21:20) +# CHECK: d1 c0 95 8c +r17 = neg(r21):sat + +# Round +# CHECK: 31 c0 d4 88 +r17 = round(r21:20):sat +# CHECK: 11 df f5 8c +r17 = cround(r21, #31) +# CHECK: 91 df f5 8c +r17 = round(r21, #31) +# CHECK: d1 df f5 8c +r17 = round(r21, #31):sat +# CHECK: 11 df d5 c6 +r17 = cround(r21, r31) +# CHECK: 91 df d5 c6 +r17 = round(r21, r31) +# CHECK: d1 df d5 c6 +r17 = round(r21, r31):sat + +# Subtract doublewords +# CHECK: f0 d4 3e d3 +r17:16 = sub(r21:20, r31:30) + +# Subtract and accumulate words +# CHECK: 71 d5 1f ef +r17 += sub(r21, r31) + +# Subtract halfword +# CHECK: 11 d5 3f d5 +r17 = sub(r21.l, r31.l) +# CHECK: 51 d5 3f d5 +r17 = sub(r21.l, r31.h) +# CHECK: 91 d5 3f d5 +r17 = sub(r21.l, r31.l):sat +# CHECK: d1 d5 3f d5 +r17 = sub(r21.l, r31.h):sat +# CHECK: 11 d5 7f d5 +r17 = sub(r21.l, r31.l):<<16 +# CHECK: 31 d5 7f d5 +r17 = sub(r21.l, r31.h):<<16 +# CHECK: 51 d5 7f d5 +r17 = sub(r21.h, r31.l):<<16 +# CHECK: 71 d5 7f d5 +r17 = sub(r21.h, r31.h):<<16 +# CHECK: 91 d5 7f d5 +r17 = sub(r21.l, r31.l):sat:<<16 +# CHECK: b1 d5 7f d5 +r17 = sub(r21.l, r31.h):sat:<<16 +# CHECK: d1 d5 7f d5 +r17 = sub(r21.h, r31.l):sat:<<16 +# CHECK: f1 d5 7f d5 +r17 = sub(r21.h, r31.h):sat:<<16 + +# Sign extend word to doubleword +# CHECK: 10 c0 55 84 +r17:16 = sxtw(r21) + +# Vector absolute value halfwords +# CHECK: 90 c0 54 80 +r17:16 = vabsh(r21:20) +# CHECK: b0 c0 54 80 +r17:16 = vabsh(r21:20):sat + +# Vector absolute value words +# CHECK: d0 c0 54 80 +r17:16 = vabsw(r21:20) +# CHECK: f0 c0 54 80 +r17:16 = vabsw(r21:20):sat + +# Vector absolute difference halfwords +# CHECK: 10 d4 7e e8 +r17:16 = vabsdiffh(r21:20, r31:30) + +# Vector absolute difference words +# CHECK: 10 d4 3e e8 +r17:16 = vabsdiffw(r21:20, r31:30) + +# Vector add halfwords +# CHECK: 50 de 14 d3 +r17:16 = vaddh(r21:20, r31:30) +# CHECK: 70 de 14 d3 +r17:16 = vaddh(r21:20, r31:30):sat +# CHECK: 90 de 14 d3 +r17:16 = vadduh(r21:20, r31:30):sat + +# Vector add halfwords with saturate and pack to unsigned bytes +# CHECK: 31 de 54 c1 +r17 = vaddhub(r21:20, r31:30):sat + +# Vector reduce add unsigned bytes +# CHECK: 30 de 54 e8 +r17:16 = vraddub(r21:20, r31:30) +# CHECK: 30 de 54 ea +r17:16 += vraddub(r21:20, r31:30) + +# Vector reduce add halfwords +# CHECK: 31 de 14 e9 +r17 = vradduh(r21:20, r31:30) +# CHECK: f1 de 34 e9 +r17 = vraddh(r21:20, r31:30) + +# Vector add bytes +# CHECK: 10 de 14 d3 +r17:16 = vaddub(r21:20, r31:30) +# CHECK: 30 de 14 d3 +r17:16 = vaddub(r21:20, r31:30):sat + +# Vector add words +# CHECK: b0 de 14 d3 +r17:16 = vaddw(r21:20, r31:30) +# CHECK: d0 de 14 d3 +r17:16 = vaddw(r21:20, r31:30):sat + +# Vector average halfwords +# CHECK: 50 de 54 d3 +r17:16 = vavgh(r21:20, r31:30) +# CHECK: 70 de 54 d3 +r17:16 = vavgh(r21:20, r31:30):rnd +# CHECK: 90 de 54 d3 +r17:16 = vavgh(r21:20, r31:30):crnd +# CHECK: b0 de 54 d3 +r17:16 = vavguh(r21:20, r31:30) +# CHECK: d0 de 54 d3 +r17:16 = vavguh(r21:20, r31:30):rnd +# CHECK: 10 d4 9e d3 +r17:16 = vnavgh(r21:20, r31:30) +# CHECK: 30 d4 9e d3 +r17:16 = vnavgh(r21:20, r31:30):rnd:sat +# CHECK: 50 d4 9e d3 +r17:16 = vnavgh(r21:20, r31:30):crnd:sat + +# Vector average unsigned bytes +# CHECK: 10 de 54 d3 +r17:16 = vavgub(r21:20, r31:30) +# CHECK: 30 de 54 d3 +r17:16 = vavgub(r21:20, r31:30):rnd + +# Vector average words +# CHECK: 10 de 74 d3 +r17:16 = vavgw(r21:20, r31:30) +# CHECK: 30 de 74 d3 +r17:16 = vavgw(r21:20, r31:30):rnd +# CHECK: 50 de 74 d3 +r17:16 = vavgw(r21:20, r31:30):crnd +# CHECK: 70 de 74 d3 +r17:16 = vavguw(r21:20, r31:30) +# CHECK: 90 de 74 d3 +r17:16 = vavguw(r21:20, r31:30):rnd +# CHECK: 70 d4 9e d3 +r17:16 = vnavgw(r21:20, r31:30) +# CHECK: 90 d4 9e d3 +r17:16 = vnavgw(r21:20, r31:30):rnd:sat +# CHECK: d0 d4 9e d3 +r17:16 = vnavgw(r21:20, r31:30):crnd:sat + +# Vector conditional negate +# CHECK: 50 df d4 c3 +r17:16 = vcnegh(r21:20, r31) + +# CHECK: f0 ff 34 cb +r17:16 += vrcnegh(r21:20, r31) + +# Vector maximum bytes +# CHECK: 10 d4 de d3 +r17:16 = vmaxub(r21:20, r31:30) +# CHECK: d0 d4 de d3 +r17:16 = vmaxb(r21:20, r31:30) + +# Vector maximum halfwords +# CHECK: 30 d4 de d3 +r17:16 = vmaxh(r21:20, r31:30) +# CHECK: 50 d4 de d3 +r17:16 = vmaxuh(r21:20, r31:30) + +# Vector reduce maximum halfwords +# CHECK: 3f d0 34 cb +r17:16 = vrmaxh(r21:20, r31) +# CHECK: 3f f0 34 cb +r17:16 = vrmaxuh(r21:20, r31) + +# Vector reduce maximum words +# CHECK: 5f d0 34 cb +r17:16 = vrmaxw(r21:20, r31) +# CHECK: 5f f0 34 cb +r17:16 = vrmaxuw(r21:20, r31) + +# Vector maximum words +# CHECK: b0 d4 be d3 +r17:16 = vmaxuw(r21:20, r31:30) +# CHECK: 70 d4 de d3 +r17:16 = vmaxw(r21:20, r31:30) + +# Vector minimum bytes +# CHECK: 10 d4 be d3 +r17:16 = vminub(r21:20, r31:30) +# CHECK: f0 d4 de d3 +r17:16 = vminb(r21:20, r31:30) + +# Vector minimum halfwords +# CHECK: 30 d4 be d3 +r17:16 = vminh(r21:20, r31:30) +# CHECK: 50 d4 be d3 +r17:16 = vminuh(r21:20, r31:30) + +# Vector reduce minimum halfwords +# CHECK: bf d0 34 cb +r17:16 = vrminh(r21:20, r31) +# CHECK: bf f0 34 cb +r17:16 = vrminuh(r21:20, r31) + +# Vector reduce minimum words +# CHECK: df d0 34 cb +r17:16 = vrminw(r21:20, r31) +# CHECK: df f0 34 cb +r17:16 = vrminuw(r21:20, r31) + +# Vector minimum words +# CHECK: 70 d4 be d3 +r17:16 = vminw(r21:20, r31:30) +# CHECK: 90 d4 be d3 +r17:16 = vminuw(r21:20, r31:30) + +# Vector sum of absolute differences unsigned bytes +# CHECK: 50 de 54 e8 +r17:16 = vrsadub(r21:20, r31:30) +# CHECK: 50 de 54 ea +r17:16 += vrsadub(r21:20, r31:30) + +# Vector subtract halfwords +# CHECK: 50 d4 3e d3 +r17:16 = vsubh(r21:20, r31:30) +# CHECK: 70 d4 3e d3 +r17:16 = vsubh(r21:20, r31:30):sat +# CHECK: 90 d4 3e d3 +r17:16 = vsubuh(r21:20, r31:30):sat + +# Vector subtract bytes +# CHECK: 10 d4 3e d3 +r17:16 = vsubub(r21:20, r31:30) +# CHECK: 30 d4 3e d3 +r17:16 = vsubub(r21:20, r31:30):sat + +# Vector subtract words +# CHECK: b0 d4 3e d3 +r17:16 = vsubw(r21:20, r31:30) +# CHECK: d0 d4 3e d3 +r17:16 = vsubw(r21:20, r31:30):sat diff --git a/test/MC/Hexagon/instructions/xtype_bit.s b/test/MC/Hexagon/instructions/xtype_bit.s new file mode 100644 index 00000000000..6d2fa401b81 --- /dev/null +++ b/test/MC/Hexagon/instructions/xtype_bit.s @@ -0,0 +1,118 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.10.2 XTYPE/BIT + +# Count leading +# CHECK: 11 c0 54 88 +r17 = clb(r21:20) +# CHECK: 51 c0 54 88 +r17 = cl0(r21:20) +# CHECK: 91 c0 54 88 +r17 = cl1(r21:20) +# CHECK: 11 c0 74 88 +r17 = normamt(r21:20) +# CHECK: 51 d7 74 88 +r17 = add(clb(r21:20), #23) +# CHECK: 11 d7 35 8c +r17 = add(clb(r21), #23) +# CHECK: 91 c0 15 8c +r17 = clb(r21) +# CHECK: b1 c0 15 8c +r17 = cl0(r21) +# CHECK: d1 c0 15 8c +r17 = cl1(r21) +# CHECK: f1 c0 15 8c +r17 = normamt(r21) + +# Count population +# CHECK: 71 c0 74 88 +r17 = popcount(r21:20) + +# Count trailing +# CHECK: 51 c0 f4 88 +r17 = ct0(r21:20) +# CHECK: 91 c0 f4 88 +r17 = ct1(r21:20) +# CHECK: 91 c0 55 8c +r17 = ct0(r21) +# CHECK: b1 c0 55 8c +r17 = ct1(r21) + +# Extract bitfield +# CHECK: f0 df 54 81 +r17:16 = extractu(r21:20, #31, #23) +# CHECK: f0 df 54 8a +r17:16 = extract(r21:20, #31, #23) +# CHECK: f1 df 55 8d +r17 = extractu(r21, #31, #23) +# CHECK: f1 df d5 8d +r17 = extract(r21, #31, #23) +# CHECK: 10 de 14 c1 +r17:16 = extractu(r21:20, r31:30) +# CHECK: 90 de d4 c1 +r17:16 = extract(r21:20, r31:30) +# CHECK: 11 de 15 c9 +r17 = extractu(r21, r31:30) +# CHECK: 51 de 15 c9 +r17 = extract(r21, r31:30) + +# Insert bitfield +# CHECK: f0 df 54 83 +r17:16 = insert(r21:20, #31, #23) +# CHECK: f1 df 55 8f +r17 = insert(r21, #31, #23) +# CHECK: 11 de 15 c8 +r17 = insert(r21, r31:30) +# CHECK: 10 de 14 ca +r17:16 = insert(r21:20, r31:30) + +# Interleave/deinterleave +# CHECK: 90 c0 d4 80 +r17:16 = deinterleave(r21:20) +# CHECK: b0 c0 d4 80 +r17:16 = interleave(r21:20) + +# Linear feedback-shift iteration +# CHECK: d0 de 94 c1 +r17:16 = lfs(r21:20, r31:30) + +# Masked parity +# CHECK: 11 de 14 d0 +r17 = parity(r21:20, r31:30) +# CHECK: 11 df f5 d5 +r17 = parity(r21, r31) + +# Bit reverse +# CHECK: d0 c0 d4 80 +r17:16 = brev(r21:20) +# CHECK: d1 c0 55 8c +r17 = brev(r21) + +# Set/clear/toggle bit +# CHECK: 11 df d5 8c +r17 = setbit(r21, #31) +# CHECK: 31 df d5 8c +r17 = clrbit(r21, #31) +# CHECK: 51 df d5 8c +r17 = togglebit(r21, #31) +# CHECK: 11 df 95 c6 +r17 = setbit(r21, r31) +# CHECK: 51 df 95 c6 +r17 = clrbit(r21, r31) +# CHECK: 91 df 95 c6 +r17 = togglebit(r21, r31) + +# Split bitfield +# CHECK: 90 df d5 88 +r17:16 = bitsplit(r21, #31) +# CHECK: 10 df 35 d4 +r17:16 = bitsplit(r21, r31) + +# Table index +# CHECK: f1 cd 15 87 +r17 = tableidxb(r21, #7, #13):raw +# CHECK: f1 cd 55 87 +r17 = tableidxh(r21, #7, #13):raw +# CHECK: f1 cd 95 87 +r17 = tableidxw(r21, #7, #13):raw +# CHECK: f1 cd d5 87 +r17 = tableidxd(r21, #7, #13):raw diff --git a/test/MC/Hexagon/instructions/xtype_complex.s b/test/MC/Hexagon/instructions/xtype_complex.s new file mode 100644 index 00000000000..901c29c80d9 --- /dev/null +++ b/test/MC/Hexagon/instructions/xtype_complex.s @@ -0,0 +1,128 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.10.3 XTYPE/COMPLEX + +# Complex add/sub halfwords +# CHECK: 90 de 54 c1 +r17:16 = vxaddsubh(r21:20, r31:30):sat +# CHECK: d0 de 54 c1 +r17:16 = vxsubaddh(r21:20, r31:30):sat +# CHECK: 10 de d4 c1 +r17:16 = vxaddsubh(r21:20, r31:30):rnd:>>1:sat +# CHECK: 50 de d4 c1 +r17:16 = vxsubaddh(r21:20, r31:30):rnd:>>1:sat + +# Complex add/sub words +# CHECK: 10 de 54 c1 +r17:16 = vxaddsubw(r21:20, r31:30):sat +# CHECK: 50 de 54 c1 +r17:16 = vxsubaddw(r21:20, r31:30):sat + +# Complex multiply +# CHECK: d0 df 15 e5 +r17:16 = cmpy(r21, r31):sat +# CHECK: d0 df 95 e5 +r17:16 = cmpy(r21, r31):<<1:sat +# CHECK: d0 df 55 e5 +r17:16 = cmpy(r21, r31*):sat +# CHECK: d0 df d5 e5 +r17:16 = cmpy(r21, r31*):<<1:sat +# CHECK: d0 df 15 e7 +r17:16 += cmpy(r21, r31):sat +# CHECK: d0 df 95 e7 +r17:16 += cmpy(r21, r31):<<1:sat +# CHECK: f0 df 15 e7 +r17:16 -= cmpy(r21, r31):sat +# CHECK: f0 df 95 e7 +r17:16 -= cmpy(r21, r31):<<1:sat +# CHECK: d0 df 55 e7 +r17:16 += cmpy(r21, r31*):sat +# CHECK: d0 df d5 e7 +r17:16 += cmpy(r21, r31*):<<1:sat +# CHECK: f0 df 55 e7 +r17:16 -= cmpy(r21, r31*):sat +# CHECK: f0 df d5 e7 +r17:16 -= cmpy(r21, r31*):<<1:sat + +# Complex multiply real or imaginary +# CHECK: 30 df 15 e5 +r17:16 = cmpyi(r21, r31) +# CHECK: 50 df 15 e5 +r17:16 = cmpyr(r21, r31) +# CHECK: 30 df 15 e7 +r17:16 += cmpyi(r21, r31) +# CHECK: 50 df 15 e7 +r17:16 += cmpyr(r21, r31) + +# Complex multiply with round and pack +# CHECK: d1 df 35 ed +r17 = cmpy(r21, r31):rnd:sat +# CHECK: d1 df b5 ed +r17 = cmpy(r21, r31):<<1:rnd:sat +# CHECK: d1 df 75 ed +r17 = cmpy(r21, r31*):rnd:sat +# CHECK: d1 df f5 ed +r17 = cmpy(r21, r31*):<<1:rnd:sat + +# Complex multiply 32x16 +# CHECK: 91 df 14 c5 +r17 = cmpyiwh(r21:20, r31):<<1:rnd:sat +# CHECK: b1 df 14 c5 +r17 = cmpyiwh(r21:20, r31*):<<1:rnd:sat +# CHECK: d1 df 14 c5 +r17 = cmpyrwh(r21:20, r31):<<1:rnd:sat +# CHECK: f1 df 14 c5 +r17 = cmpyrwh(r21:20, r31*):<<1:rnd:sat + +# Vector complex multiply real or imaginary +# CHECK: d0 de 34 e8 +r17:16 = vcmpyr(r21:20, r31:30):sat +# CHECK: d0 de b4 e8 +r17:16 = vcmpyr(r21:20, r31:30):<<1:sat +# CHECK: d0 de 54 e8 +r17:16 = vcmpyi(r21:20, r31:30):sat +# CHECK: d0 de d4 e8 +r17:16 = vcmpyi(r21:20, r31:30):<<1:sat +# CHECK: 90 de 34 ea +r17:16 += vcmpyr(r21:20, r31:30):sat +# CHECK: 90 de 54 ea +r17:16 += vcmpyi(r21:20, r31:30):sat + +# Vector complex conjugate +# CHECK: f0 c0 94 80 +r17:16 = vconj(r21:20):sat + +# Vector complex rotate +# CHECK: 10 df d4 c3 +r17:16 = vcrotate(r21:20, r31) + +# Vector reduce complex multiply real or imaginary +# CHECK: 10 de 14 e8 +r17:16 = vrcmpyi(r21:20, r31:30) +# CHECK: 30 de 14 e8 +r17:16 = vrcmpyr(r21:20, r31:30) +# CHECK: 10 de 54 e8 +r17:16 = vrcmpyi(r21:20, r31:30*) +# CHECK: 30 de 74 e8 +r17:16 = vrcmpyr(r21:20, r31:30*) + +# Vector reduce complex multiply by scalar +# CHECK: 90 de b4 e8 +r17:16 = vrcmpys(r21:20, r31:30):<<1:sat:raw:hi +# CHECK: 90 de f4 e8 +r17:16 = vrcmpys(r21:20, r31:30):<<1:sat:raw:lo +# CHECK: 90 de b4 ea +r17:16 += vrcmpys(r21:20, r31:30):<<1:sat:raw:hi +# CHECK: 90 de f4 ea +r17:16 += vrcmpys(r21:20, r31:30):<<1:sat:raw:lo + +# Vector reduce complex multiply by scalar with round and pack +# CHECK: d1 de b4 e9 +r17 = vrcmpys(r21:20, r31:30):<<1:rnd:sat:raw:hi +# CHECK: f1 de b4 e9 +r17 = vrcmpys(r21:20, r31:30):<<1:rnd:sat:raw:lo + +# Vector reduce complex rotate +# CHECK: f0 ff d4 c3 +r17:16 = vrcrotate(r21:20, r31, #3) +# CHECK: 30 ff b4 cb +r17:16 += vrcrotate(r21:20, r31, #3) diff --git a/test/MC/Hexagon/instructions/xtype_fp.s b/test/MC/Hexagon/instructions/xtype_fp.s new file mode 100644 index 00000000000..184098ec6d0 --- /dev/null +++ b/test/MC/Hexagon/instructions/xtype_fp.s @@ -0,0 +1,146 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.10.4 XTYPE/FP + +# Floating point addition +# CHECK: 11 df 15 eb +r17 = sfadd(r21, r31) + +# Classify floating-point value +# CHECK: 03 d5 f1 85 +p3 = sfclass(r17, #21) +# CHECK: b3 c2 90 dc +p3 = dfclass(r17:16, #21) + +# Compare floating-point value +# CHECK: 03 d5 f1 c7 +p3 = sfcmp.ge(r17, r21) +# CHECK: 23 d5 f1 c7 +p3 = sfcmp.uo(r17, r21) +# CHECK: 63 d5 f1 c7 +p3 = sfcmp.eq(r17, r21) +# CHECK: 83 d5 f1 c7 +p3 = sfcmp.gt(r17, r21) +# CHECK: 03 d4 f0 d2 +p3 = dfcmp.eq(r17:16, r21:20) +# CHECK: 23 d4 f0 d2 +p3 = dfcmp.gt(r17:16, r21:20) +# CHECK: 43 d4 f0 d2 +p3 = dfcmp.ge(r17:16, r21:20) +# CHECK: 63 d4 f0 d2 +p3 = dfcmp.uo(r17:16, r21:20) + +# Convert floating-point value to other format +# CHECK: 10 c0 95 84 +r17:16 = convert_sf2df(r21) +# CHECK: 31 c0 14 88 +r17 = convert_df2sf(r21:20) + +# Convert integer to floating-point value +# CHECK: 50 c0 f4 80 +r17:16 = convert_ud2df(r21:20) +# CHECK: 70 c0 f4 80 +r17:16 = convert_d2df(r21:20) +# CHECK: 30 c0 95 84 +r17:16 = convert_uw2df(r21) +# CHECK: 50 c0 95 84 +r17:16 = convert_w2df(r21) +# CHECK: 31 c0 34 88 +r17 = convert_ud2sf(r21:20) +# CHECK: 31 c0 54 88 +r17 = convert_d2sf(r21:20) +# CHECK: 11 c0 35 8b +r17 = convert_uw2sf(r21) +# CHECK: 11 c0 55 8b +r17 = convert_w2sf(r21) + +# Convert floating-point value to integer +# CHECK: 10 c0 f4 80 +r17:16 = convert_df2d(r21:20) +# CHECK: 30 c0 f4 80 +r17:16 = convert_df2ud(r21:20) +# CHECK: d0 c0 f4 80 +r17:16 = convert_df2d(r21:20):chop +# CHECK: f0 c0 f4 80 +r17:16 = convert_df2ud(r21:20):chop +# CHECK: 70 c0 95 84 +r17:16 = convert_sf2ud(r21) +# CHECK: 90 c0 95 84 +r17:16 = convert_sf2d(r21) +# CHECK: b0 c0 95 84 +r17:16 = convert_sf2ud(r21):chop +# CHECK: d0 c0 95 84 +r17:16 = convert_sf2d(r21):chop +# CHECK: 31 c0 74 88 +r17 = convert_df2uw(r21:20) +# CHECK: 31 c0 94 88 +r17 = convert_df2w(r21:20) +# CHECK: 31 c0 b4 88 +r17 = convert_df2uw(r21:20):chop +# CHECK: 31 c0 f4 88 +r17 = convert_df2w(r21:20):chop +# CHECK: 11 c0 75 8b +r17 = convert_sf2uw(r21) +# CHECK: 31 c0 75 8b +r17 = convert_sf2uw(r21):chop +# CHECK: 11 c0 95 8b +r17 = convert_sf2w(r21) +# CHECK: 31 c0 95 8b +r17 = convert_sf2w(r21):chop + +# Floating point extreme value assistance +# CHECK: 11 c0 b5 8b +r17 = sffixupr(r21) +# CHECK: 11 df d5 eb +r17 = sffixupn(r21, r31) +# CHECK: 31 df d5 eb +r17 = sffixupd(r21, r31) + +# Floating point fused multiply-add +# CHECK: 91 df 15 ef +r17 += sfmpy(r21, r31) +# CHECK: b1 df 15 ef +r17 -= sfmpy(r21, r31) + +# Floating point fused multiply-add with scaling +# CHECK: f1 df 75 ef +r17 += sfmpy(r21, r31, p3):scale + +# Floating point reciprocal square root approximation +# CHECK: 71 c0 f5 8b +r17, p3 = sfinvsqrta(r21) + +# Floating point fused multiply-add for library routines +# CHECK: d1 df 15 ef +r17 += sfmpy(r21, r31):lib +# CHECK: f1 df 15 ef +r17 -= sfmpy(r21, r31):lib + +# Create floating-point constant +# CHECK: b1 c2 00 d6 +r17 = sfmake(#21):pos +# CHECK: b1 c2 40 d6 +r17 = sfmake(#21):neg +# CHECK: b0 c2 00 d9 +r17:16 = dfmake(#21):pos +# CHECK: b0 c2 40 d9 +r17:16 = dfmake(#21):neg + +# Floating point maximum +# CHECK: 11 df 95 eb +r17 = sfmax(r21, r31) + +# Floating point minimum +# CHECK: 31 df 95 eb +r17 = sfmin(r21, r31) + +# Floating point multiply +# CHECK: 11 df 55 eb +r17 = sfmpy(r21, r31) + +# Floating point reciprocal approximation +# CHECK: f1 df f5 eb +r17, p3 = sfrecipa(r21, r31) + +# Floating point subtraction +# CHECK: 31 df 15 eb +r17 = sfsub(r21, r31) diff --git a/test/MC/Hexagon/instructions/xtype_mpy.s b/test/MC/Hexagon/instructions/xtype_mpy.s new file mode 100644 index 00000000000..4b9efd4cabc --- /dev/null +++ b/test/MC/Hexagon/instructions/xtype_mpy.s @@ -0,0 +1,400 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.10.5 XTYPE/MPY + +# Multiply and use lower result +# CHECK: b1 df 35 d7 +r17 = add(#21, mpyi(r21, r31)) +# CHECK: bf d1 35 d8 +r17 = add(#21, mpyi(r21, #31)) +# CHECK: b5 d1 3f df +r17 = add(r21, mpyi(#84, r31)) +# CHECK: f5 f1 b5 df +r17 = add(r21, mpyi(r21, #31)) +# CHECK: 15 d1 1f e3 +r17 = add(r21, mpyi(r17, r31)) +# CHECK: f1 c3 15 e0 +r17 =+ mpyi(r21, #31) +# CHECK: f1 c3 95 e0 +r17 =- mpyi(r21, #31) +# CHECK: f1 c3 15 e1 +r17 += mpyi(r21, #31) +# CHECK: f1 c3 95 e1 +r17 -= mpyi(r21, #31) +# CHECK: 11 df 15 ed +r17 = mpyi(r21, r31) +# CHECK: 11 df 15 ef +r17 += mpyi(r21, r31) + +# Vector multiply word by signed half (32x16) +# CHECK: b0 de 14 e8 +r17:16 = vmpyweh(r21:20, r31:30):sat +# CHECK: b0 de 94 e8 +r17:16 = vmpyweh(r21:20, r31:30):<<1:sat +# CHECK: f0 de 14 e8 +r17:16 = vmpywoh(r21:20, r31:30):sat +# CHECK: f0 de 94 e8 +r17:16 = vmpywoh(r21:20, r31:30):<<1:sat +# CHECK: b0 de 34 e8 +r17:16 = vmpyweh(r21:20, r31:30):rnd:sat +# CHECK: b0 de b4 e8 +r17:16 = vmpyweh(r21:20, r31:30):<<1:rnd:sat +# CHECK: f0 de 34 e8 +r17:16 = vmpywoh(r21:20, r31:30):rnd:sat +# CHECK: f0 de b4 e8 +r17:16 = vmpywoh(r21:20, r31:30):<<1:rnd:sat +# CHECK: b0 de 14 ea +r17:16 += vmpyweh(r21:20, r31:30):sat +# CHECK: b0 de 94 ea +r17:16 += vmpyweh(r21:20, r31:30):<<1:sat +# CHECK: f0 de 14 ea +r17:16 += vmpywoh(r21:20, r31:30):sat +# CHECK: f0 de 94 ea +r17:16 += vmpywoh(r21:20, r31:30):<<1:sat +# CHECK: b0 de 34 ea +r17:16 += vmpyweh(r21:20, r31:30):rnd:sat +# CHECK: b0 de b4 ea +r17:16 += vmpyweh(r21:20, r31:30):<<1:rnd:sat +# CHECK: f0 de 34 ea +r17:16 += vmpywoh(r21:20, r31:30):rnd:sat +# CHECK: f0 de b4 ea +r17:16 += vmpywoh(r21:20, r31:30):<<1:rnd:sat + +# Vector multiply word by unsigned half (32x16) +# CHECK: b0 de 54 e8 +r17:16 = vmpyweuh(r21:20, r31:30):sat +# CHECK: b0 de d4 e8 +r17:16 = vmpyweuh(r21:20, r31:30):<<1:sat +# CHECK: f0 de 54 e8 +r17:16 = vmpywouh(r21:20, r31:30):sat +# CHECK: f0 de d4 e8 +r17:16 = vmpywouh(r21:20, r31:30):<<1:sat +# CHECK: b0 de 74 e8 +r17:16 = vmpyweuh(r21:20, r31:30):rnd:sat +# CHECK: b0 de f4 e8 +r17:16 = vmpyweuh(r21:20, r31:30):<<1:rnd:sat +# CHECK: f0 de 74 e8 +r17:16 = vmpywouh(r21:20, r31:30):rnd:sat +# CHECK: f0 de f4 e8 +r17:16 = vmpywouh(r21:20, r31:30):<<1:rnd:sat +# CHECK: b0 de 54 ea +r17:16 += vmpyweuh(r21:20, r31:30):sat +# CHECK: b0 de d4 ea +r17:16 += vmpyweuh(r21:20, r31:30):<<1:sat +# CHECK: f0 de 54 ea +r17:16 += vmpywouh(r21:20, r31:30):sat +# CHECK: f0 de d4 ea +r17:16 += vmpywouh(r21:20, r31:30):<<1:sat +# CHECK: b0 de 74 ea +r17:16 += vmpyweuh(r21:20, r31:30):rnd:sat +# CHECK: b0 de f4 ea +r17:16 += vmpyweuh(r21:20, r31:30):<<1:rnd:sat +# CHECK: f0 de 74 ea +r17:16 += vmpywouh(r21:20, r31:30):rnd:sat +# CHECK: f0 de f4 ea +r17:16 += vmpywouh(r21:20, r31:30):<<1:rnd:sat + +# Multiply signed halfwords +# CHECK: 10 df 95 e4 +r17:16 = mpy(r21.l, r31.l):<<1 +# CHECK: 30 df 95 e4 +r17:16 = mpy(r21.l, r31.h):<<1 +# CHECK: 50 df 95 e4 +r17:16 = mpy(r21.h, r31.l):<<1 +# CHECK: 70 df 95 e4 +r17:16 = mpy(r21.h, r31.h):<<1 +# CHECK: 10 df b5 e4 +r17:16 = mpy(r21.l, r31.l):<<1:rnd +# CHECK: 30 df b5 e4 +r17:16 = mpy(r21.l, r31.h):<<1:rnd +# CHECK: 50 df b5 e4 +r17:16 = mpy(r21.h, r31.l):<<1:rnd +# CHECK: 70 df b5 e4 +r17:16 = mpy(r21.h, r31.h):<<1:rnd +# CHECK: 10 df 95 e6 +r17:16 += mpy(r21.l, r31.l):<<1 +# CHECK: 30 df 95 e6 +r17:16 += mpy(r21.l, r31.h):<<1 +# CHECK: 50 df 95 e6 +r17:16 += mpy(r21.h, r31.l):<<1 +# CHECK: 70 df 95 e6 +r17:16 += mpy(r21.h, r31.h):<<1 +# CHECK: 10 df b5 e6 +r17:16 -= mpy(r21.l, r31.l):<<1 +# CHECK: 30 df b5 e6 +r17:16 -= mpy(r21.l, r31.h):<<1 +# CHECK: 50 df b5 e6 +r17:16 -= mpy(r21.h, r31.l):<<1 +# CHECK: 70 df b5 e6 +r17:16 -= mpy(r21.h, r31.h):<<1 +# CHECK: 11 df 95 ec +r17 = mpy(r21.l, r31.l):<<1 +# CHECK: 31 df 95 ec +r17 = mpy(r21.l, r31.h):<<1 +# CHECK: 51 df 95 ec +r17 = mpy(r21.h, r31.l):<<1 +# CHECK: 71 df 95 ec +r17 = mpy(r21.h, r31.h):<<1 +# CHECK: 91 df 95 ec +r17 = mpy(r21.l, r31.l):<<1:sat +# CHECK: b1 df 95 ec +r17 = mpy(r21.l, r31.h):<<1:sat +# CHECK: d1 df 95 ec +r17 = mpy(r21.h, r31.l):<<1:sat +# CHECK: f1 df 95 ec +r17 = mpy(r21.h, r31.h):<<1:sat +# CHECK: 11 df b5 ec +r17 = mpy(r21.l, r31.l):<<1:rnd +# CHECK: 31 df b5 ec +r17 = mpy(r21.l, r31.h):<<1:rnd +# CHECK: 51 df b5 ec +r17 = mpy(r21.h, r31.l):<<1:rnd +# CHECK: 71 df b5 ec +r17 = mpy(r21.h, r31.h):<<1:rnd +# CHECK: 91 df b5 ec +r17 = mpy(r21.l, r31.l):<<1:rnd:sat +# CHECK: b1 df b5 ec +r17 = mpy(r21.l, r31.h):<<1:rnd:sat +# CHECK: d1 df b5 ec +r17 = mpy(r21.h, r31.l):<<1:rnd:sat +# CHECK: f1 df b5 ec +r17 = mpy(r21.h, r31.h):<<1:rnd:sat +# CHECK: 11 df 95 ee +r17 += mpy(r21.l, r31.l):<<1 +# CHECK: 31 df 95 ee +r17 += mpy(r21.l, r31.h):<<1 +# CHECK: 51 df 95 ee +r17 += mpy(r21.h, r31.l):<<1 +# CHECK: 71 df 95 ee +r17 += mpy(r21.h, r31.h):<<1 +# CHECK: 91 df 95 ee +r17 += mpy(r21.l, r31.l):<<1:sat +# CHECK: b1 df 95 ee +r17 += mpy(r21.l, r31.h):<<1:sat +# CHECK: d1 df 95 ee +r17 += mpy(r21.h, r31.l):<<1:sat +# CHECK: f1 df 95 ee +r17 += mpy(r21.h, r31.h):<<1:sat +# CHECK: 11 df b5 ee +r17 -= mpy(r21.l, r31.l):<<1 +# CHECK: 31 df b5 ee +r17 -= mpy(r21.l, r31.h):<<1 +# CHECK: 51 df b5 ee +r17 -= mpy(r21.h, r31.l):<<1 +# CHECK: 71 df b5 ee +r17 -= mpy(r21.h, r31.h):<<1 +# CHECK: 91 df b5 ee +r17 -= mpy(r21.l, r31.l):<<1:sat +# CHECK: b1 df b5 ee +r17 -= mpy(r21.l, r31.h):<<1:sat +# CHECK: d1 df b5 ee +r17 -= mpy(r21.h, r31.l):<<1:sat +# CHECK: f1 df b5 ee +r17 -= mpy(r21.h, r31.h):<<1:sat + +# Multiply unsigned halfwords +# CHECK: 10 df d5 e4 +r17:16 = mpyu(r21.l, r31.l):<<1 +# CHECK: 30 df d5 e4 +r17:16 = mpyu(r21.l, r31.h):<<1 +# CHECK: 50 df d5 e4 +r17:16 = mpyu(r21.h, r31.l):<<1 +# CHECK: 70 df d5 e4 +r17:16 = mpyu(r21.h, r31.h):<<1 +# CHECK: 10 df d5 e6 +r17:16 += mpyu(r21.l, r31.l):<<1 +# CHECK: 30 df d5 e6 +r17:16 += mpyu(r21.l, r31.h):<<1 +# CHECK: 50 df d5 e6 +r17:16 += mpyu(r21.h, r31.l):<<1 +# CHECK: 70 df d5 e6 +r17:16 += mpyu(r21.h, r31.h):<<1 +# CHECK: 10 df f5 e6 +r17:16 -= mpyu(r21.l, r31.l):<<1 +# CHECK: 30 df f5 e6 +r17:16 -= mpyu(r21.l, r31.h):<<1 +# CHECK: 50 df f5 e6 +r17:16 -= mpyu(r21.h, r31.l):<<1 +# CHECK: 70 df f5 e6 +r17:16 -= mpyu(r21.h, r31.h):<<1 +# CHECK: 11 df d5 ec +r17 = mpyu(r21.l, r31.l):<<1 +# CHECK: 31 df d5 ec +r17 = mpyu(r21.l, r31.h):<<1 +# CHECK: 51 df d5 ec +r17 = mpyu(r21.h, r31.l):<<1 +# CHECK: 71 df d5 ec +r17 = mpyu(r21.h, r31.h):<<1 +# CHECK: 11 df d5 ee +r17 += mpyu(r21.l, r31.l):<<1 +# CHECK: 31 df d5 ee +r17 += mpyu(r21.l, r31.h):<<1 +# CHECK: 51 df d5 ee +r17 += mpyu(r21.h, r31.l):<<1 +# CHECK: 71 df d5 ee +r17 += mpyu(r21.h, r31.h):<<1 +# CHECK: 11 df f5 ee +r17 -= mpyu(r21.l, r31.l):<<1 +# CHECK: 31 df f5 ee +r17 -= mpyu(r21.l, r31.h):<<1 +# CHECK: 51 df f5 ee +r17 -= mpyu(r21.h, r31.l):<<1 +# CHECK: 71 df f5 ee +r17 -= mpyu(r21.h, r31.h):<<1 + +# Polynomial multiply words +# CHECK: f0 df 55 e5 +r17:16 = pmpyw(r21, r31) +# CHECK: f0 df 35 e7 +r17:16 ^= pmpyw(r21, r31) + +# Vector reduce multiply word by signed half (32x16) +# CHECK: 50 de 34 e8 +r17:16 = vrmpywoh(r21:20, r31:30) +# CHECK: 50 de b4 e8 +r17:16 = vrmpywoh(r21:20, r31:30):<<1 +# CHECK: 90 de 54 e8 +r17:16 = vrmpyweh(r21:20, r31:30) +# CHECK: 90 de d4 e8 +r17:16 = vrmpyweh(r21:20, r31:30):<<1 +# CHECK: d0 de 74 ea +r17:16 += vrmpywoh(r21:20, r31:30) +# CHECK: d0 de f4 ea +r17:16 += vrmpywoh(r21:20, r31:30):<<1 +# CHECK: d0 de 34 ea +r17:16 += vrmpyweh(r21:20, r31:30) +# CHECK: d0 de b4 ea +r17:16 += vrmpyweh(r21:20, r31:30):<<1 + +# Multiply and use upper result +# CHECK: 31 df 15 ed +r17 = mpy(r21, r31) +# CHECK: 31 df 35 ed +r17 = mpy(r21, r31):rnd +# CHECK: 31 df 55 ed +r17 = mpyu(r21, r31) +# CHECK: 31 df 75 ed +r17 = mpysu(r21, r31) +# CHECK: 11 df b5 ed +r17 = mpy(r21, r31.h):<<1:sat +# CHECK: 31 df b5 ed +r17 = mpy(r21, r31.l):<<1:sat +# CHECK: 91 df b5 ed +r17 = mpy(r21, r31.h):<<1:rnd:sat +# CHECK: 11 df f5 ed +r17 = mpy(r21, r31):<<1:sat +# CHECK: 91 df f5 ed +r17 = mpy(r21, r31.l):<<1:rnd:sat +# CHECK: 51 df b5 ed +r17 = mpy(r21, r31):<<1 +# CHECK: 11 df 75 ef +r17 += mpy(r21, r31):<<1:sat +# CHECK: 31 df 75 ef +r17 -= mpy(r21, r31):<<1:sat + +# Multiply and use full result +# CHECK: 10 df 15 e5 +r17:16 = mpy(r21, r31) +# CHECK: 10 df 55 e5 +r17:16 = mpyu(r21, r31) +# CHECK: 10 df 15 e7 +r17:16 += mpy(r21, r31) +# CHECK: 10 df 35 e7 +r17:16 -= mpy(r21, r31) +# CHECK: 10 df 55 e7 +r17:16 += mpyu(r21, r31) +# CHECK: 10 df 75 e7 +r17:16 -= mpyu(r21, r31) + +# Vector dual multiply +# CHECK: 90 de 14 e8 +r17:16 = vdmpy(r21:20, r31:30):sat +# CHECK: 90 de 94 e8 +r17:16 = vdmpy(r21:20, r31:30):<<1:sat +# CHECK: 90 de 14 ea +r17:16 += vdmpy(r21:20, r31:30):sat +# CHECK: 90 de 94 ea +r17:16 += vdmpy(r21:20, r31:30):<<1:sat + +# Vector dual multiply with round and pack +# CHECK: 11 de 14 e9 +r17 = vdmpy(r21:20, r31:30):rnd:sat +# CHECK: 11 de 94 e9 +r17 = vdmpy(r21:20, r31:30):<<1:rnd:sat + +# Vector reduce multiply bytes +# CHECK: 30 de 94 e8 +r17:16 = vrmpybu(r21:20, r31:30) +# CHECK: 30 de d4 e8 +r17:16 = vrmpybsu(r21:20, r31:30) +# CHECK: 30 de 94 ea +r17:16 += vrmpybu(r21:20, r31:30) +# CHECK: 30 de d4 ea +r17:16 += vrmpybsu(r21:20, r31:30) + +# Vector dual multiply signed by unsigned bytes +# CHECK: 30 de b4 e8 +r17:16 = vdmpybsu(r21:20, r31:30):sat +# CHECK: 30 de 34 ea +r17:16 += vdmpybsu(r21:20, r31:30):sat + +# Vector multiply even haldwords +# CHECK: d0 de 14 e8 +r17:16 = vmpyeh(r21:20, r31:30):sat +# CHECK: d0 de 94 e8 +r17:16 = vmpyeh(r21:20, r31:30):<<1:sat +# CHECK: 50 de 34 ea +r17:16 += vmpyeh(r21:20, r31:30) +# CHECK: d0 de 14 ea +r17:16 += vmpyeh(r21:20, r31:30):sat +# CHECK: d0 de 94 ea +r17:16 += vmpyeh(r21:20, r31:30):<<1:sat + +# Vector multiply halfwords +# CHECK: b0 df 15 e5 +r17:16 = vmpyh(r21, r31):sat +# CHECK: b0 df 95 e5 +r17:16 = vmpyh(r21, r31):<<1:sat +# CHECK: 30 df 35 e7 +r17:16 += vmpyh(r21, r31) +# CHECK: b0 df 15 e7 +r17:16 += vmpyh(r21, r31):sat +# CHECK: b0 df 95 e7 +r17:16 += vmpyh(r21, r31):<<1:sat + +# Vector multiply halfwords with round and pack +# CHECK: f1 df 35 ed +r17 = vmpyh(r21, r31):rnd:sat +# CHECK: f1 df b5 ed +r17 = vmpyh(r21, r31):<<1:rnd:sat + +# Vector multiply halfwords signed by unsigned +# CHECK: f0 df 15 e5 +r17:16 = vmpyhsu(r21, r31):sat +# CHECK: f0 df 95 e5 +r17:16 = vmpyhsu(r21, r31):<<1:sat +# CHECK: b0 df 75 e7 +r17:16 += vmpyhsu(r21, r31):sat +# CHECK: b0 df f5 e7 +r17:16 += vmpyhsu(r21, r31):<<1:sat + +# Vector reduce multiply halfwords +# CHECK: 50 de 14 e8 +r17:16 = vrmpyh(r21:20, r31:30) +# CHECK: 50 de 14 ea +r17:16 += vrmpyh(r21:20, r31:30) + +# Vector multiply bytes +# CHECK: 30 df 55 e5 +r17:16 = vmpybsu(r21, r31) +# CHECK: 30 df 95 e5 +r17:16 = vmpybu(r21, r31) +# CHECK: 30 df 95 e7 +r17:16 += vmpybu(r21, r31) +# CHECK: 30 df d5 e7 +r17:16 += vmpybsu(r21, r31) + +# Vector polynomial multiply halfwords +# CHECK: f0 df d5 e5 +r17:16 = vpmpyh(r21, r31) +# CHECK: f0 df b5 e7 +r17:16 ^= vpmpyh(r21, r31) diff --git a/test/MC/Hexagon/instructions/xtype_perm.s b/test/MC/Hexagon/instructions/xtype_perm.s new file mode 100644 index 00000000000..d8033ec8017 --- /dev/null +++ b/test/MC/Hexagon/instructions/xtype_perm.s @@ -0,0 +1,104 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.10.6 XTYPE/PERM + +# CABAC decode bin +# CHECK: d0 de d4 c1 +r17:16 = decbin(r21:20, r31:30) + +# Saturate +# CHECK: 11 c0 d4 88 +r17 = sat(r21:20) +# CHECK: 91 c0 d5 8c +r17 = sath(r21) +# CHECK: b1 c0 d5 8c +r17 = satuh(r21) +# CHECK: d1 c0 d5 8c +r17 = satub(r21) +# CHECK: f1 c0 d5 8c +r17 = satb(r21) + +# Swizzle bytes +# CHECK: f1 c0 95 8c +r17 = swiz(r21) + +# Vector align +# CHECK: 70 d4 1e c2 +r17:16 = valignb(r21:20, r31:30, p3) +# CHECK: 70 de 94 c2 +r17:16 = vspliceb(r21:20, r31:30, p3) + +# Vector round and pack +# CHECK: 91 c0 94 88 +r17 = vrndwh(r21:20) +# CHECK: d1 c0 94 88 +r17 = vrndwh(r21:20):sat + +# Vector saturate and pack +# CHECK: 11 c0 14 88 +r17 = vsathub(r21:20) +# CHECK: 51 c0 14 88 +r17 = vsatwh(r21:20) +# CHECK: 91 c0 14 88 +r17 = vsatwuh(r21:20) +# CHECK: d1 c0 14 88 +r17 = vsathb(r21:20) +# CHECK: 11 c0 95 8c +r17 = vsathb(r21) +# CHECK: 51 c0 95 8c +r17 = vsathub(r21) + +# Vector saturate without pack +# CHECK: 90 c0 14 80 +r17:16 = vsathub(r21:20) +# CHECK: b0 c0 14 80 +r17:16 = vsatwuh(r21:20) +# CHECK: d0 c0 14 80 +r17:16 = vsatwh(r21:20) +# CHECK: f0 c0 14 80 +r17:16 = vsathb(r21:20) + +# Vector shuffle +# CHECK: 50 de 14 c1 +r17:16 = shuffeb(r21:20, r31:30) +# CHECK: 90 d4 1e c1 +r17:16 = shuffob(r21:20, r31:30) +# CHECK: d0 de 14 c1 +r17:16 = shuffeh(r21:20, r31:30) +# CHECK: 10 d4 9e c1 +r17:16 = shuffoh(r21:20, r31:30) + +# Vector splat bytes +# CHECK: f1 c0 55 8c +r17 = vsplatb(r21) + +# Vector splat halfwords +# CHECK: 50 c0 55 84 +r17:16 = vsplath(r21) + +# Vector splice +# CHECK: 70 de 94 c0 +r17:16 = vspliceb(r21:20, r31:30, #3) +# CHECK: 70 de 94 c2 +r17:16 = vspliceb(r21:20, r31:30, p3) + +# Vector sign extend +# CHECK: 10 c0 15 84 +r17:16 = vsxtbh(r21) +# CHECK: 90 c0 15 84 +r17:16 = vsxthw(r21) + +# Vector truncate +# CHECK: 11 c0 94 88 +r17 = vtrunohb(r21:20) +# CHECK: 51 c0 94 88 +r17 = vtrunehb(r21:20) +# CHECK: 50 de 94 c1 +r17:16 = vtrunewh(r21:20, r31:30) +# CHECK: 90 de 94 c1 +r17:16 = vtrunowh(r21:20, r31:30) + +# Vector zero extend +# CHECK: 50 c0 15 84 +r17:16 = vzxtbh(r21) +# CHECK: d0 c0 15 84 +r17:16 = vzxthw(r21) diff --git a/test/MC/Hexagon/instructions/xtype_pred.s b/test/MC/Hexagon/instructions/xtype_pred.s new file mode 100644 index 00000000000..769de0f6e02 --- /dev/null +++ b/test/MC/Hexagon/instructions/xtype_pred.s @@ -0,0 +1,136 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.10.7 XTYPE/PRED + +# Bounds check +# CHECK: 83 f4 10 d2 +p3 = boundscheck(r17:16, r21:20):raw:lo +# CHECK: a3 f4 10 d2 +p3 = boundscheck(r17:16, r21:20):raw:hi + +# Compare byte +# CHECK: 43 d5 d1 c7 +p3 = cmpb.gt(r17, r21) +# CHECK: c3 d5 d1 c7 +p3 = cmpb.eq(r17, r21) +# CHECK: e3 d5 d1 c7 +p3 = cmpb.gtu(r17, r21) +# CHECK: a3 c2 11 dd +p3 = cmpb.eq(r17, #21) +# CHECK: a3 c2 31 dd +p3 = cmpb.gt(r17, #21) +# CHECK: a3 c2 51 dd +p3 = cmpb.gtu(r17, #21) + +# Compare half +# CHECK: 63 d5 d1 c7 +p3 = cmph.eq(r17, r21) +# CHECK: 83 d5 d1 c7 +p3 = cmph.gt(r17, r21) +# CHECK: a3 d5 d1 c7 +p3 = cmph.gtu(r17, r21) +# CHECK: ab c2 11 dd +p3 = cmph.eq(r17, #21) +# CHECK: ab c2 31 dd +p3 = cmph.gt(r17, #21) +# CHECK: ab c2 51 dd +p3 = cmph.gtu(r17, #21) + +# Compare doublewords +# CHECK: 03 de 94 d2 +p3 = cmp.eq(r21:20, r31:30) +# CHECK: 43 de 94 d2 +p3 = cmp.gt(r21:20, r31:30) +# CHECK: 83 de 94 d2 +p3 = cmp.gtu(r21:20, r31:30) + +# Compare bitmask +# CHECK: 03 d5 91 85 +p3 = bitsclr(r17, #21) +# CHECK: 03 d5 b1 85 +p3 = !bitsclr(r17, #21) +# CHECK: 03 d5 51 c7 +p3 = bitsset(r17, r21) +# CHECK: 03 d5 71 c7 +p3 = !bitsset(r17, r21) +# CHECK: 03 d5 91 c7 +p3 = bitsclr(r17, r21) +# CHECK: 03 d5 b1 c7 +p3 = !bitsclr(r17, r21) + +# mask generate from predicate +# CHECK: 10 c3 00 86 +r17:16 = mask(p3) + +# Check for TLB match +# CHECK: 63 f5 10 d2 +p3 = tlbmatch(r17:16, r21) + +# Predicate Transfer +# CHECK: 03 c0 45 85 +p3 = r5 +# CHECK: 05 c0 43 89 +r5 = p3 + +# Test bit +# CHECK: 03 d5 11 85 +p3 = tstbit(r17, #21) +# CHECK: 03 d5 31 85 +p3 = !tstbit(r17, #21) +# CHECK: 03 d5 11 c7 +p3 = tstbit(r17, r21) +# CHECK: 03 d5 31 c7 +p3 = !tstbit(r17, r21) + +# Vector compare halfwords +# CHECK: 63 de 14 d2 +p3 = vcmph.eq(r21:20, r31:30) +# CHECK: 83 de 14 d2 +p3 = vcmph.gt(r21:20, r31:30) +# CHECK: a3 de 14 d2 +p3 = vcmph.gtu(r21:20, r31:30) +# CHECK: eb c3 14 dc +p3 = vcmph.eq(r21:20, #31) +# CHECK: eb c3 34 dc +p3 = vcmph.gt(r21:20, #31) +# CHECK: eb c3 54 dc +p3 = vcmph.gtu(r21:20, #31) + +# Vector compare bytes for any match +# CHECK: 03 fe 14 d2 +p3 = any8(vcmpb.eq(r21:20, r31:30)) + +# Vector compare bytes +# CHECK: 63 de 14 d2 +p3 = vcmph.eq(r21:20, r31:30) +# CHECK: 83 de 14 d2 +p3 = vcmph.gt(r21:20, r31:30) +# CHECK: a3 de 14 d2 +p3 = vcmph.gtu(r21:20, r31:30) +# CHECK: eb c3 14 dc +p3 = vcmph.eq(r21:20, #31) +# CHECK: eb c3 34 dc +p3 = vcmph.gt(r21:20, #31) +# CHECK: eb c3 54 dc +p3 = vcmph.gtu(r21:20, #31) + +# Vector compare words +# CHECK: 03 de 14 d2 +p3 = vcmpw.eq(r21:20, r31:30) +# CHECK: 23 de 14 d2 +p3 = vcmpw.gt(r21:20, r31:30) +# CHECK: 43 de 14 d2 +p3 = vcmpw.gtu(r21:20, r31:30) +# CHECK: f3 c3 14 dc +p3 = vcmpw.eq(r21:20, #31) +# CHECK: f3 c3 34 dc +p3 = vcmpw.gt(r21:20, #31) +# CHECK: f3 c3 54 dc +p3 = vcmpw.gtu(r21:20, #31) + +# Viterbi pack even and odd predicate bits +# CHECK: 11 c2 03 89 +r17 = vitpack(p3, p2) + +# Vector mux +# CHECK: 70 de 14 d1 +r17:16 = vmux(p3, r21:20, r31:30) diff --git a/test/MC/Hexagon/instructions/xtype_shift.s b/test/MC/Hexagon/instructions/xtype_shift.s new file mode 100644 index 00000000000..bbe327b62ba --- /dev/null +++ b/test/MC/Hexagon/instructions/xtype_shift.s @@ -0,0 +1,260 @@ +# RUN: llvm-mc -triple=hexagon -filetype=obj -o - %s | llvm-objdump -d - | FileCheck %s +# Hexagon Programmer's Reference Manual 11.10.8 XTYPE/SHIFT + +# Shift by immediate +# CHECK: 10 df 14 80 +r17:16 = asr(r21:20, #31) +# CHECK: 30 df 14 80 +r17:16 = lsr(r21:20, #31) +# CHECK: 50 df 14 80 +r17:16 = asl(r21:20, #31) +# CHECK: 11 df 15 8c +r17 = asr(r21, #31) +# CHECK: 31 df 15 8c +r17 = lsr(r21, #31) +# CHECK: 51 df 15 8c +r17 = asl(r21, #31) + +# Shift by immediate and accumulate +# CHECK: 10 df 14 82 +r17:16 -= asr(r21:20, #31) +# CHECK: 30 df 14 82 +r17:16 -= lsr(r21:20, #31) +# CHECK: 50 df 14 82 +r17:16 -= asl(r21:20, #31) +# CHECK: 90 df 14 82 +r17:16 += asr(r21:20, #31) +# CHECK: b0 df 14 82 +r17:16 += lsr(r21:20, #31) +# CHECK: d0 df 14 82 +r17:16 += asl(r21:20, #31) +# CHECK: 11 df 15 8e +r17 -= asr(r21, #31) +# CHECK: 31 df 15 8e +r17 -= lsr(r21, #31) +# CHECK: 51 df 15 8e +r17 -= asl(r21, #31) +# CHECK: 91 df 15 8e +r17 += asr(r21, #31) +# CHECK: b1 df 15 8e +r17 += lsr(r21, #31) +# CHECK: d1 df 15 8e +r17 += asl(r21, #31) +# CHECK: 4c f7 11 de +r17 = add(#21, asl(r17, #23)) +# CHECK: 4e f7 11 de +r17 = sub(#21, asl(r17, #23)) +# CHECK: 5c f7 11 de +r17 = add(#21, lsr(r17, #23)) +# CHECK: 5e f7 11 de +r17 = sub(#21, lsr(r17, #23)) + +# Shift by immediate and add +# CHECK: f1 d5 1f c4 +r17 = addasl(r21, r31, #7) + +# Shift by immediate and logical +# CHECK: 10 df 54 82 +r17:16 &= asr(r21:20, #31) +# CHECK: 30 df 54 82 +r17:16 &= lsr(r21:20, #31) +# CHECK: 50 df 54 82 +r17:16 &= asl(r21:20, #31) +# CHECK: 90 df 54 82 +r17:16 |= asr(r21:20, #31) +# CHECK: b0 df 54 82 +r17:16 |= lsr(r21:20, #31) +# CHECK: d0 df 54 82 +r17:16 |= asl(r21:20, #31) +# CHECK: 30 df 94 82 +r17:16 ^= lsr(r21:20, #31) +# CHECK: 50 df 94 82 +r17:16 ^= asl(r21:20, #31) +# CHECK: 11 df 55 8e +r17 &= asr(r21, #31) +# CHECK: 31 df 55 8e +r17 &= lsr(r21, #31) +# CHECK: 51 df 55 8e +r17 &= asl(r21, #31) +# CHECK: 91 df 55 8e +r17 |= asr(r21, #31) +# CHECK: b1 df 55 8e +r17 |= lsr(r21, #31) +# CHECK: d1 df 55 8e +r17 |= asl(r21, #31) +# CHECK: 31 df 95 8e +r17 ^= lsr(r21, #31) +# CHECK: 51 df 95 8e +r17 ^= asl(r21, #31) +# CHECK: 48 ff 11 de +r17 = and(#21, asl(r17, #31)) +# CHECK: 4a ff 11 de +r17 = or(#21, asl(r17, #31)) +# CHECK: 58 ff 11 de +r17 = and(#21, lsr(r17, #31)) +# CHECK: 5a ff 11 de +r17 = or(#21, lsr(r17, #31)) + +# Shift right by immediate with rounding +# CHECK: f0 df d4 80 +r17:16 = asr(r21:20, #31):rnd +# CHECK: 11 df 55 8c +r17 = asr(r21, #31):rnd + +# Shift left by immediate with saturation +# CHECK: 51 df 55 8c +r17 = asl(r21, #31):sat + +# Shift by register +# CHECK: 10 df 94 c3 +r17:16 = asr(r21:20, r31) +# CHECK: 50 df 94 c3 +r17:16 = lsr(r21:20, r31) +# CHECK: 90 df 94 c3 +r17:16 = asl(r21:20, r31) +# CHECK: d0 df 94 c3 +r17:16 = lsl(r21:20, r31) +# CHECK: 11 df 55 c6 +r17 = asr(r21, r31) +# CHECK: 51 df 55 c6 +r17 = lsr(r21, r31) +# CHECK: 91 df 55 c6 +r17 = asl(r21, r31) +# CHECK: d1 df 55 c6 +r17 = lsl(r21, r31) +# CHECK: f1 df 8a c6 +r17 = lsl(#21, r31) + +# Shift by register and accumulate +# CHECK: 10 df 94 cb +r17:16 -= asr(r21:20, r31) +# CHECK: 50 df 94 cb +r17:16 -= lsr(r21:20, r31) +# CHECK: 90 df 94 cb +r17:16 -= asl(r21:20, r31) +# CHECK: d0 df 94 cb +r17:16 -= lsl(r21:20, r31) +# CHECK: 10 df d4 cb +r17:16 += asr(r21:20, r31) +# CHECK: 50 df d4 cb +r17:16 += lsr(r21:20, r31) +# CHECK: 90 df d4 cb +r17:16 += asl(r21:20, r31) +# CHECK: d0 df d4 cb +r17:16 += lsl(r21:20, r31) +# CHECK: 11 df 95 cc +r17 -= asr(r21, r31) +# CHECK: 51 df 95 cc +r17 -= lsr(r21, r31) +# CHECK: 91 df 95 cc +r17 -= asl(r21, r31) +# CHECK: d1 df 95 cc +r17 -= lsl(r21, r31) +# CHECK: 11 df d5 cc +r17 += asr(r21, r31) +# CHECK: 51 df d5 cc +r17 += lsr(r21, r31) +# CHECK: 91 df d5 cc +r17 += asl(r21, r31) +# CHECK: d1 df d5 cc +r17 += lsl(r21, r31) + +# Shift by register and logical +# CHECK: 10 df 14 cb +r17:16 |= asr(r21:20, r31) +# CHECK: 50 df 14 cb +r17:16 |= lsr(r21:20, r31) +# CHECK: 90 df 14 cb +r17:16 |= asl(r21:20, r31) +# CHECK: d0 df 14 cb +r17:16 |= lsl(r21:20, r31) +# CHECK: 10 df 54 cb +r17:16 &= asr(r21:20, r31) +# CHECK: 50 df 54 cb +r17:16 &= lsr(r21:20, r31) +# CHECK: 90 df 54 cb +r17:16 &= asl(r21:20, r31) +# CHECK: d0 df 54 cb +r17:16 &= lsl(r21:20, r31) +# CHECK: 10 df 74 cb +r17:16 ^= asr(r21:20, r31) +# CHECK: 50 df 74 cb +r17:16 ^= lsr(r21:20, r31) +# CHECK: 90 df 74 cb +r17:16 ^= asl(r21:20, r31) +# CHECK: d0 df 74 cb +r17:16 ^= lsl(r21:20, r31) +# CHECK: 11 df 15 cc +r17 |= asr(r21, r31) +# CHECK: 51 df 15 cc +r17 |= lsr(r21, r31) +# CHECK: 91 df 15 cc +r17 |= asl(r21, r31) +# CHECK: d1 df 15 cc +r17 |= lsl(r21, r31) +# CHECK: 11 df 55 cc +r17 &= asr(r21, r31) +# CHECK: 51 df 55 cc +r17 &= lsr(r21, r31) +# CHECK: 91 df 55 cc +r17 &= asl(r21, r31) +# CHECK: d1 df 55 cc +r17 &= lsl(r21, r31) + +# Shift by register with saturation +# CHECK: 11 df 15 c6 +r17 = asr(r21, r31):sat +# CHECK: 91 df 15 c6 +r17 = asl(r21, r31):sat + +# Vector shift halfwords by immediate +# CHECK: 10 c5 94 80 +r17:16 = vasrh(r21:20, #5) +# CHECK: 30 c5 94 80 +r17:16 = vlsrh(r21:20, #5) +# CHECK: 50 c5 94 80 +r17:16 = vaslh(r21:20, #5) + +# Vector arithmetic shift halfwords with round +# CHECK: 10 c5 34 80 +r17:16 = vasrh(r21:20, #5):raw + +# Vector arithmetic shift halfwords with saturate and pack +# CHECK: 91 c5 74 88 +r17 = vasrhub(r21:20, #5):raw +# CHECK: b1 c5 74 88 +r17 = vasrhub(r21:20, #5):sat + +# Vector shift halfwords by register +# CHECK: 10 df 54 c3 +r17:16 = vasrh(r21:20, r31) +# CHECK: 50 df 54 c3 +r17:16 = vlsrh(r21:20, r31) +# CHECK: 90 df 54 c3 +r17:16 = vaslh(r21:20, r31) +# CHECK: d0 df 54 c3 +r17:16 = vlslh(r21:20, r31) + +# Vector shift words by immediate +# CHECK: 10 df 54 80 +r17:16 = vasrw(r21:20, #31) +# CHECK: 30 df 54 80 +r17:16 = vlsrw(r21:20, #31) +# CHECK: 50 df 54 80 +r17:16 = vaslw(r21:20, #31) + +# Vector shift words by register +# CHECK: 10 df 14 c3 +r17:16 = vasrw(r21:20, r31) +# CHECK: 50 df 14 c3 +r17:16 = vlsrw(r21:20, r31) +# CHECK: 90 df 14 c3 +r17:16 = vaslw(r21:20, r31) +# CHECK: d0 df 14 c3 +r17:16 = vlslw(r21:20, r31) + +# Vector shift words with truncate and pack +# CHECK: 51 df d4 88 +r17 = vasrw(r21:20, #31) +# CHECK: 51 df 14 c5 +r17 = vasrw(r21:20, r31)