
This is a mechanical change. This actually also renames the similarly named methods in the SmallString class, however these methods don't seem to be used outside of the llvm subproject, so this doesn't break building of the rest of the monorepo.
2006 lines
70 KiB
C++
2006 lines
70 KiB
C++
//===-- HexagonAsmParser.cpp - Parse Hexagon asm to MCInst instructions----===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "HexagonTargetStreamer.h"
|
|
#include "MCTargetDesc/HexagonMCChecker.h"
|
|
#include "MCTargetDesc/HexagonMCELFStreamer.h"
|
|
#include "MCTargetDesc/HexagonMCExpr.h"
|
|
#include "MCTargetDesc/HexagonMCInstrInfo.h"
|
|
#include "MCTargetDesc/HexagonMCTargetDesc.h"
|
|
#include "MCTargetDesc/HexagonShuffler.h"
|
|
#include "TargetInfo/HexagonTargetInfo.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/BinaryFormat/ELF.h"
|
|
#include "llvm/MC/MCAssembler.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCDirectives.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/MCAsmParserExtension.h"
|
|
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
|
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
#include "llvm/MC/MCSectionELF.h"
|
|
#include "llvm/MC/MCStreamer.h"
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
#include "llvm/MC/MCSymbol.h"
|
|
#include "llvm/MC/MCValue.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
#include "llvm/Support/SMLoc.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cctype>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#define DEBUG_TYPE "mcasmparser"
|
|
|
|
using namespace llvm;
|
|
|
|
static cl::opt<bool> WarnMissingParenthesis(
|
|
"mwarn-missing-parenthesis",
|
|
cl::desc("Warn for missing parenthesis around predicate registers"),
|
|
cl::init(true));
|
|
static cl::opt<bool> ErrorMissingParenthesis(
|
|
"merror-missing-parenthesis",
|
|
cl::desc("Error for missing parenthesis around predicate registers"),
|
|
cl::init(false));
|
|
static cl::opt<bool> WarnSignedMismatch(
|
|
"mwarn-sign-mismatch",
|
|
cl::desc("Warn for mismatching a signed and unsigned value"),
|
|
cl::init(true));
|
|
static cl::opt<bool> WarnNoncontigiousRegister(
|
|
"mwarn-noncontigious-register",
|
|
cl::desc("Warn for register names that arent contigious"), cl::init(true));
|
|
static cl::opt<bool> 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<HexagonTargetStreamer &>(TS);
|
|
}
|
|
|
|
MCAsmParser &Parser;
|
|
MCInst MCB;
|
|
bool InBrackets;
|
|
|
|
MCAsmParser &getParser() const { return Parser; }
|
|
MCAssembler *getAssembler() const {
|
|
MCAssembler *Assembler = nullptr;
|
|
// FIXME: need better way to detect AsmStreamer (upstream removed getKind())
|
|
if (!Parser.getStreamer().hasRawTextSupport()) {
|
|
MCELFStreamer *MES = static_cast<MCELFStreamer *>(&Parser.getStreamer());
|
|
Assembler = &MES->getAssembler();
|
|
}
|
|
return Assembler;
|
|
}
|
|
|
|
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
|
|
|
|
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);
|
|
|
|
bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
|
|
OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc,
|
|
SMLoc &EndLoc) override;
|
|
bool ParseDirectiveSubsection(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);
|
|
void eatToEndOfPacket();
|
|
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
|
OperandVector &Operands, MCStreamer &Out,
|
|
uint64_t &ErrorInfo,
|
|
bool MatchingInlineAsm) override;
|
|
|
|
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
|
|
unsigned Kind) override;
|
|
bool OutOfRange(SMLoc IDLoc, long long Val, long long Max);
|
|
int processInstruction(MCInst &Inst, OperandVector const &Operands,
|
|
SMLoc IDLoc);
|
|
|
|
// Check if we have an assembler and, if so, set the ELF e_header flags.
|
|
void chksetELFHeaderEFlags(unsigned flags) {
|
|
if (getAssembler())
|
|
getAssembler()->setELFHeaderEFlags(flags);
|
|
}
|
|
|
|
unsigned matchRegister(StringRef Name);
|
|
|
|
/// @name Auto-generated Match Functions
|
|
/// {
|
|
|
|
#define GET_ASSEMBLER_HEADER
|
|
#include "HexagonGenAsmMatcher.inc"
|
|
|
|
/// }
|
|
|
|
public:
|
|
HexagonAsmParser(const MCSubtargetInfo &_STI, MCAsmParser &_Parser,
|
|
const MCInstrInfo &MII, const MCTargetOptions &Options)
|
|
: MCTargetAsmParser(Options, _STI, MII), Parser(_Parser),
|
|
InBrackets(false) {
|
|
MCB.setOpcode(Hexagon::BUNDLE);
|
|
setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits()));
|
|
|
|
Parser.addAliasForDirective(".half", ".2byte");
|
|
Parser.addAliasForDirective(".hword", ".2byte");
|
|
Parser.addAliasForDirective(".word", ".4byte");
|
|
|
|
MCAsmParserExtension::Initialize(_Parser);
|
|
}
|
|
|
|
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);
|
|
|
|
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
|
SMLoc NameLoc, OperandVector &Operands) override {
|
|
llvm_unreachable("Unimplemented");
|
|
}
|
|
|
|
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, AsmToken ID,
|
|
OperandVector &Operands) override;
|
|
|
|
bool ParseDirective(AsmToken DirectiveID) override;
|
|
};
|
|
|
|
/// HexagonOperand - Instances of this class represent a parsed Hexagon machine
|
|
/// instruction.
|
|
struct HexagonOperand : public MCParsedAsmOperand {
|
|
enum KindTy { Token, Immediate, Register } Kind;
|
|
MCContext &Context;
|
|
|
|
SMLoc StartLoc, EndLoc;
|
|
|
|
struct TokTy {
|
|
const char *Data;
|
|
unsigned Length;
|
|
};
|
|
|
|
struct RegTy {
|
|
unsigned RegNum;
|
|
};
|
|
|
|
struct ImmTy {
|
|
const MCExpr *Val;
|
|
};
|
|
|
|
struct InstTy {
|
|
OperandVector *SubInsts;
|
|
};
|
|
|
|
union {
|
|
struct TokTy Tok;
|
|
struct RegTy Reg;
|
|
struct ImmTy Imm;
|
|
};
|
|
|
|
HexagonOperand(KindTy K, MCContext &Context)
|
|
: MCParsedAsmOperand(), Kind(K), Context(Context) {}
|
|
|
|
public:
|
|
HexagonOperand(const HexagonOperand &o)
|
|
: MCParsedAsmOperand(), Context(o.Context) {
|
|
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 override { return StartLoc; }
|
|
|
|
/// getEndLoc - Get the location of the last token of this operand.
|
|
SMLoc getEndLoc() const override { return EndLoc; }
|
|
|
|
unsigned getReg() const override {
|
|
assert(Kind == Register && "Invalid access!");
|
|
return Reg.RegNum;
|
|
}
|
|
|
|
const MCExpr *getImm() const {
|
|
assert(Kind == Immediate && "Invalid access!");
|
|
return Imm.Val;
|
|
}
|
|
|
|
bool isToken() const override { return Kind == Token; }
|
|
bool isImm() const override { return Kind == Immediate; }
|
|
bool isMem() const override { llvm_unreachable("No isMem"); }
|
|
bool isReg() const override { return Kind == Register; }
|
|
|
|
bool CheckImmRange(int immBits, int zeroBits, bool isSigned,
|
|
bool isRelocatable, bool Extendable) const {
|
|
if (Kind == Immediate) {
|
|
const MCExpr *myMCExpr = &HexagonMCInstrInfo::getExpr(*getImm());
|
|
if (HexagonMCInstrInfo::mustExtend(*Imm.Val) && !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));
|
|
else {
|
|
const int64_t high_bit_set = 1ULL << 63;
|
|
const uint64_t mask = (high_bit_set >> (63 - bits));
|
|
return (((uint64_t)Res & mask) == mask);
|
|
}
|
|
}
|
|
} else if (myMCExpr->getKind() == MCExpr::SymbolRef && isRelocatable)
|
|
return true;
|
|
else if (myMCExpr->getKind() == MCExpr::Binary ||
|
|
myMCExpr->getKind() == MCExpr::Unary)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool isa30_2Imm() const { return CheckImmRange(30, 2, true, true, true); }
|
|
bool isb30_2Imm() const { return CheckImmRange(30, 2, true, true, true); }
|
|
bool isb15_2Imm() const { return CheckImmRange(15, 2, true, true, false); }
|
|
bool isb13_2Imm() const { return CheckImmRange(13, 2, true, true, false); }
|
|
|
|
bool ism32_0Imm() const { return true; }
|
|
|
|
bool isf32Imm() const { return false; }
|
|
bool isf64Imm() const { return false; }
|
|
bool iss32_0Imm() const { return true; }
|
|
bool iss31_1Imm() const { return true; }
|
|
bool iss30_2Imm() const { return true; }
|
|
bool iss29_3Imm() const { return true; }
|
|
bool iss27_2Imm() const { return CheckImmRange(27, 2, true, true, false); }
|
|
bool iss10_0Imm() const { return CheckImmRange(10, 0, true, false, false); }
|
|
bool iss10_6Imm() const { return CheckImmRange(10, 6, true, false, false); }
|
|
bool iss9_0Imm() const { return CheckImmRange(9, 0, true, false, false); }
|
|
bool iss8_0Imm() const { return CheckImmRange(8, 0, true, false, false); }
|
|
bool iss8_0Imm64() const { return CheckImmRange(8, 0, true, true, false); }
|
|
bool iss7_0Imm() const { return CheckImmRange(7, 0, true, false, false); }
|
|
bool iss6_0Imm() const { return CheckImmRange(6, 0, true, false, false); }
|
|
bool iss6_3Imm() const { return CheckImmRange(6, 3, 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 iss3_0Imm() const { return CheckImmRange(3, 0, true, false, false); }
|
|
|
|
bool isu64_0Imm() const { return CheckImmRange(64, 0, false, true, true); }
|
|
bool isu32_0Imm() const { return true; }
|
|
bool isu31_1Imm() const { return true; }
|
|
bool isu30_2Imm() const { return true; }
|
|
bool isu29_3Imm() const { return true; }
|
|
bool isu26_6Imm() const { return CheckImmRange(26, 6, 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 isu10_0Imm() const { return CheckImmRange(10, 0, false, false, false); }
|
|
bool isu9_0Imm() const { return CheckImmRange(9, 0, false, false, false); }
|
|
bool isu8_0Imm() const { return CheckImmRange(8, 0, false, false, false); }
|
|
bool isu7_0Imm() const { return CheckImmRange(7, 0, 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 isu5_0Imm() const { return CheckImmRange(5, 0, false, false, false); }
|
|
bool isu5_2Imm() const { return CheckImmRange(5, 2, false, false, false); }
|
|
bool isu5_3Imm() const { return CheckImmRange(5, 3, false, false, false); }
|
|
bool isu4_0Imm() const { return CheckImmRange(4, 0, false, false, false); }
|
|
bool isu4_2Imm() const { return CheckImmRange(4, 2, false, false, false); }
|
|
bool isu3_0Imm() const { return CheckImmRange(3, 0, false, false, false); }
|
|
bool isu3_1Imm() const { return CheckImmRange(3, 1, false, false, false); }
|
|
bool isu2_0Imm() const { return CheckImmRange(2, 0, false, false, false); }
|
|
bool isu1_0Imm() const { return CheckImmRange(1, 0, false, false, false); }
|
|
|
|
bool isn1Const() const {
|
|
if (!isImm())
|
|
return false;
|
|
int64_t Value;
|
|
if (!getImm()->evaluateAsAbsolute(Value))
|
|
return false;
|
|
return Value == -1;
|
|
}
|
|
bool iss11_0Imm() const {
|
|
return CheckImmRange(11 + 26, 0, true, true, true);
|
|
}
|
|
bool iss11_1Imm() const {
|
|
return CheckImmRange(11 + 26, 1, true, true, true);
|
|
}
|
|
bool iss11_2Imm() const {
|
|
return CheckImmRange(11 + 26, 2, true, true, true);
|
|
}
|
|
bool iss11_3Imm() const {
|
|
return CheckImmRange(11 + 26, 3, true, true, true);
|
|
}
|
|
bool isu32_0MustExt() const { return isImm(); }
|
|
|
|
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!");
|
|
HexagonMCExpr *Expr =
|
|
const_cast<HexagonMCExpr *>(cast<HexagonMCExpr>(getImm()));
|
|
int64_t Value;
|
|
if (!Expr->evaluateAsAbsolute(Value)) {
|
|
Inst.addOperand(MCOperand::createExpr(Expr));
|
|
return;
|
|
}
|
|
int64_t Extended = SignExtend64(Value, 32);
|
|
HexagonMCExpr *NewExpr = HexagonMCExpr::create(
|
|
MCConstantExpr::create(Extended, Context), Context);
|
|
if ((Extended < 0) != (Value < 0))
|
|
NewExpr->setSignMismatch();
|
|
NewExpr->setMustExtend(Expr->mustExtend());
|
|
NewExpr->setMustNotExtend(Expr->mustNotExtend());
|
|
Inst.addOperand(MCOperand::createExpr(NewExpr));
|
|
}
|
|
|
|
void addn1ConstOperands(MCInst &Inst, unsigned N) const {
|
|
addImmOperands(Inst, N);
|
|
}
|
|
|
|
StringRef getToken() const {
|
|
assert(Kind == Token && "Invalid access!");
|
|
return StringRef(Tok.Data, Tok.Length);
|
|
}
|
|
|
|
void print(raw_ostream &OS) const override;
|
|
|
|
static std::unique_ptr<HexagonOperand> CreateToken(MCContext &Context,
|
|
StringRef Str, SMLoc S) {
|
|
HexagonOperand *Op = new HexagonOperand(Token, Context);
|
|
Op->Tok.Data = Str.data();
|
|
Op->Tok.Length = Str.size();
|
|
Op->StartLoc = S;
|
|
Op->EndLoc = S;
|
|
return std::unique_ptr<HexagonOperand>(Op);
|
|
}
|
|
|
|
static std::unique_ptr<HexagonOperand>
|
|
CreateReg(MCContext &Context, unsigned RegNum, SMLoc S, SMLoc E) {
|
|
HexagonOperand *Op = new HexagonOperand(Register, Context);
|
|
Op->Reg.RegNum = RegNum;
|
|
Op->StartLoc = S;
|
|
Op->EndLoc = E;
|
|
return std::unique_ptr<HexagonOperand>(Op);
|
|
}
|
|
|
|
static std::unique_ptr<HexagonOperand>
|
|
CreateImm(MCContext &Context, const MCExpr *Val, SMLoc S, SMLoc E) {
|
|
HexagonOperand *Op = new HexagonOperand(Immediate, Context);
|
|
Op->Imm.Val = Val;
|
|
Op->StartLoc = S;
|
|
Op->EndLoc = E;
|
|
return std::unique_ptr<HexagonOperand>(Op);
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
void HexagonOperand::print(raw_ostream &OS) const {
|
|
switch (Kind) {
|
|
case Immediate:
|
|
getImm()->print(OS, nullptr);
|
|
break;
|
|
case Register:
|
|
OS << "<register R";
|
|
OS << getReg() << ">";
|
|
break;
|
|
case Token:
|
|
OS << "'" << getToken() << "'";
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool HexagonAsmParser::finishBundle(SMLoc IDLoc, MCStreamer &Out) {
|
|
LLVM_DEBUG(dbgs() << "Bundle:");
|
|
LLVM_DEBUG(MCB.dump_pretty(dbgs()));
|
|
LLVM_DEBUG(dbgs() << "--\n");
|
|
|
|
MCB.setLoc(IDLoc);
|
|
|
|
// Check the bundle for errors.
|
|
const MCRegisterInfo *RI = getContext().getRegisterInfo();
|
|
MCSubtargetInfo const &STI = getSTI();
|
|
|
|
MCInst OrigBundle = MCB;
|
|
HexagonMCChecker Check(getContext(), MII, STI, MCB, *RI, true);
|
|
|
|
bool CheckOk = HexagonMCInstrInfo::canonicalizePacket(
|
|
MII, STI, getContext(), MCB, &Check, true);
|
|
|
|
if (CheckOk) {
|
|
if (HexagonMCInstrInfo::bundleSize(MCB) == 0) {
|
|
assert(!HexagonMCInstrInfo::isInnerLoop(MCB));
|
|
assert(!HexagonMCInstrInfo::isOuterLoop(MCB));
|
|
// Empty packets are valid yet aren't emitted
|
|
return false;
|
|
}
|
|
|
|
assert(HexagonMCInstrInfo::isBundle(MCB));
|
|
|
|
Out.emitInstruction(MCB, STI);
|
|
} else
|
|
return true; // Error
|
|
|
|
return false; // No error
|
|
}
|
|
|
|
bool HexagonAsmParser::matchBundleOptions() {
|
|
MCAsmParser &Parser = getParser();
|
|
while (true) {
|
|
if (!Parser.getTok().is(AsmToken::Colon))
|
|
return false;
|
|
Lex();
|
|
char const *MemNoShuffMsg =
|
|
"invalid instruction packet: mem_noshuf specifier not "
|
|
"supported with this architecture";
|
|
StringRef Option = Parser.getTok().getString();
|
|
auto IDLoc = Parser.getTok().getLoc();
|
|
if (Option.compare_insensitive("endloop01") == 0) {
|
|
HexagonMCInstrInfo::setInnerLoop(MCB);
|
|
HexagonMCInstrInfo::setOuterLoop(MCB);
|
|
} else if (Option.compare_insensitive("endloop0") == 0) {
|
|
HexagonMCInstrInfo::setInnerLoop(MCB);
|
|
} else if (Option.compare_insensitive("endloop1") == 0) {
|
|
HexagonMCInstrInfo::setOuterLoop(MCB);
|
|
} else if (Option.compare_insensitive("mem_noshuf") == 0) {
|
|
if (getSTI().getFeatureBits()[Hexagon::FeatureMemNoShuf])
|
|
HexagonMCInstrInfo::setMemReorderDisabled(MCB);
|
|
else
|
|
return getParser().Error(IDLoc, MemNoShuffMsg);
|
|
} else if (Option.compare_insensitive("mem_no_order") == 0) {
|
|
// Nothing.
|
|
} else
|
|
return getParser().Error(IDLoc, llvm::Twine("'") + Option +
|
|
"' is not a valid bundle option");
|
|
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());
|
|
NewInst.addOperand(MCOperand::createExpr(HexagonMCExpr::create(
|
|
MCConstantExpr::create(Value, getContext()), getContext())));
|
|
} else {
|
|
if (I.isExpr() && cast<HexagonMCExpr>(I.getExpr())->signMismatch() &&
|
|
WarnSignedMismatch)
|
|
Warning(MCI.getLoc(), "Signed/Unsigned mismatch");
|
|
NewInst.addOperand(I);
|
|
}
|
|
MCI = NewInst;
|
|
}
|
|
|
|
bool HexagonAsmParser::matchOneInstruction(MCInst &MCI, SMLoc IDLoc,
|
|
OperandVector &InstOperands,
|
|
uint64_t &ErrorInfo,
|
|
bool MatchingInlineAsm) {
|
|
// Perform matching with tablegen asmmatcher generated function
|
|
int result =
|
|
MatchInstructionImpl(InstOperands, MCI, ErrorInfo, MatchingInlineAsm);
|
|
if (result == Match_Success) {
|
|
MCI.setLoc(IDLoc);
|
|
canonicalizeImmediates(MCI);
|
|
result = processInstruction(MCI, InstOperands, IDLoc);
|
|
|
|
LLVM_DEBUG(dbgs() << "Insn:");
|
|
LLVM_DEBUG(MCI.dump_pretty(dbgs()));
|
|
LLVM_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:
|
|
LLVM_FALLTHROUGH;
|
|
case Match_InvalidTiedOperand:
|
|
SMLoc ErrorLoc = IDLoc;
|
|
if (ErrorInfo != ~0U) {
|
|
if (ErrorInfo >= InstOperands.size())
|
|
return Error(IDLoc, "too few operands for instruction");
|
|
|
|
ErrorLoc = (static_cast<HexagonOperand *>(InstOperands[ErrorInfo].get()))
|
|
->getStartLoc();
|
|
if (ErrorLoc == SMLoc())
|
|
ErrorLoc = IDLoc;
|
|
}
|
|
return Error(ErrorLoc, "invalid operand for instruction");
|
|
}
|
|
llvm_unreachable("Implement any new match types added!");
|
|
}
|
|
|
|
void HexagonAsmParser::eatToEndOfPacket() {
|
|
assert(InBrackets);
|
|
MCAsmLexer &Lexer = getLexer();
|
|
while (!Lexer.is(AsmToken::RCurly))
|
|
Lexer.Lex();
|
|
Lexer.Lex();
|
|
InBrackets = false;
|
|
}
|
|
|
|
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<HexagonOperand &>(*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");
|
|
InBrackets = false;
|
|
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 = getParser().getContext().createMCInst();
|
|
if (matchOneInstruction(*SubInst, IDLoc, Operands, ErrorInfo,
|
|
MatchingInlineAsm)) {
|
|
if (InBrackets)
|
|
eatToEndOfPacket();
|
|
return true;
|
|
}
|
|
HexagonMCInstrInfo::extendIfNeeded(
|
|
getParser().getContext(), MII, MCB, *SubInst);
|
|
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() == ".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 = nullptr;
|
|
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 = HexagonMCExpr::create(
|
|
MCConstantExpr::create(8192 + Res, getContext()), getContext());
|
|
|
|
getStreamer().SubSection(Subsection);
|
|
return false;
|
|
}
|
|
|
|
/// ::= .falign [expression]
|
|
bool HexagonAsmParser::ParseDirectiveFalign(unsigned Size, SMLoc L) {
|
|
|
|
int64_t MaxBytesToFill = 15;
|
|
|
|
// if there is an argument
|
|
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)) {
|
|
// Make sure this is a number that is in range
|
|
auto *MCE = cast<MCConstantExpr>(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;
|
|
}
|
|
|
|
// 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<HexagonMCELFStreamer &>(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 {
|
|
if (HexagonMCRegisterClasses[Hexagon::V62RegsRegClassID].contains(MatchNum))
|
|
if (!getSTI().getFeatureBits()[Hexagon::ArchV62])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeHexagonAsmLexer();
|
|
|
|
/// Force static initialization.
|
|
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeHexagonAsmParser() {
|
|
RegisterMCAsmParser<HexagonAsmParser> X(getTheHexagonTarget());
|
|
}
|
|
|
|
#define GET_MATCHER_IMPLEMENTATION
|
|
#define GET_REGISTER_MATCHER
|
|
#include "HexagonGenAsmMatcher.inc"
|
|
|
|
static 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<HexagonOperand &>(Operand).getToken().equals_insensitive(
|
|
String);
|
|
}
|
|
|
|
static 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();
|
|
Lex();
|
|
do {
|
|
std::pair<StringRef, StringRef> HeadTail = String.split('.');
|
|
if (!HeadTail.first.empty())
|
|
Operands.push_back(
|
|
HexagonOperand::CreateToken(getContext(), HeadTail.first, Loc));
|
|
if (!HeadTail.second.empty())
|
|
Operands.push_back(HexagonOperand::CreateToken(
|
|
getContext(), 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(getContext(), LParen, Begin));
|
|
Operands.push_back(
|
|
HexagonOperand::CreateReg(getContext(), Register, Begin, End));
|
|
const AsmToken &MaybeDotNew = Lexer.getTok();
|
|
if (MaybeDotNew.is(AsmToken::TokenKind::Identifier) &&
|
|
MaybeDotNew.getString().equals_insensitive(".new"))
|
|
splitIdentifier(Operands);
|
|
Operands.push_back(
|
|
HexagonOperand::CreateToken(getContext(), 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(
|
|
getContext(), LParen, Begin));
|
|
Operands.push_back(
|
|
HexagonOperand::CreateReg(getContext(), Register, Begin, End));
|
|
const AsmToken &MaybeDotNew = Lexer.getTok();
|
|
if (MaybeDotNew.is(AsmToken::TokenKind::Identifier) &&
|
|
MaybeDotNew.getString().equals_insensitive(".new"))
|
|
splitIdentifier(Operands);
|
|
Operands.push_back(
|
|
HexagonOperand::CreateToken(getContext(), RParen, Begin));
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
Operands.push_back(
|
|
HexagonOperand::CreateReg(getContext(), 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;
|
|
// special case for parsing vwhist256:sat
|
|
if (String.lower() == "vwhist256" && Second.is(AsmToken::Colon) &&
|
|
Third.getString().lower() == "sat")
|
|
return false;
|
|
if (!Token.is(AsmToken::TokenKind::Identifier))
|
|
return true;
|
|
if (!matchRegister(String.lower()))
|
|
return true;
|
|
assert(Second.is(AsmToken::Colon));
|
|
StringRef Raw(String.data(), Third.getString().data() - String.data() +
|
|
Third.getString().size());
|
|
std::string Collapsed = std::string(Raw);
|
|
llvm::erase_if(Collapsed, isSpace);
|
|
StringRef Whole = Collapsed;
|
|
std::pair<StringRef, StringRef> DotSplit = Whole.split('.');
|
|
if (!matchRegister(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) {
|
|
return tryParseRegister(RegNo, StartLoc, EndLoc) != MatchOperand_Success;
|
|
}
|
|
|
|
OperandMatchResultTy HexagonAsmParser::tryParseRegister(unsigned &RegNo,
|
|
SMLoc &StartLoc,
|
|
SMLoc &EndLoc) {
|
|
MCAsmLexer &Lexer = getLexer();
|
|
StartLoc = getLexer().getLoc();
|
|
SmallVector<AsmToken, 5> 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 = std::string(RawString);
|
|
llvm::erase_if(Collapsed, isSpace);
|
|
StringRef FullString = Collapsed;
|
|
std::pair<StringRef, StringRef> DotSplit = FullString.split('.');
|
|
unsigned DotReg = matchRegister(DotSplit.first.lower());
|
|
if (DotReg != Hexagon::NoRegister && RegisterMatchesArch(DotReg)) {
|
|
if (DotSplit.second.empty()) {
|
|
RegNo = DotReg;
|
|
EndLoc = Lexer.getLoc();
|
|
if (handleNoncontigiousRegister(!NeededWorkaround, StartLoc))
|
|
return MatchOperand_NoMatch;
|
|
return MatchOperand_Success;
|
|
} 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 MatchOperand_NoMatch;
|
|
return MatchOperand_Success;
|
|
}
|
|
}
|
|
std::pair<StringRef, StringRef> ColonSplit = StringRef(FullString).split(':');
|
|
unsigned ColonReg = matchRegister(ColonSplit.first.lower());
|
|
if (ColonReg != Hexagon::NoRegister && RegisterMatchesArch(DotReg)) {
|
|
do {
|
|
Lexer.UnLex(Lookahead.pop_back_val());
|
|
} while (!Lookahead.empty() && !Lexer.is(AsmToken::Colon));
|
|
RegNo = ColonReg;
|
|
EndLoc = Lexer.getLoc();
|
|
if (handleNoncontigiousRegister(!NeededWorkaround, StartLoc))
|
|
return MatchOperand_NoMatch;
|
|
return MatchOperand_Success;
|
|
}
|
|
while (!Lookahead.empty()) {
|
|
Lexer.UnLex(Lookahead.pop_back_val());
|
|
}
|
|
return MatchOperand_NoMatch;
|
|
}
|
|
|
|
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) {
|
|
SmallVector<AsmToken, 4> Tokens;
|
|
MCAsmLexer &Lexer = getLexer();
|
|
bool Done = false;
|
|
static char const *Comma = ",";
|
|
do {
|
|
Tokens.emplace_back(Lexer.getTok());
|
|
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();
|
|
}
|
|
SMLoc Loc = Lexer.getLoc();
|
|
return getParser().parseExpression(Expr, Loc);
|
|
}
|
|
|
|
bool HexagonAsmParser::parseExpressionOrOperand(OperandVector &Operands) {
|
|
if (implicitExpressionLocation(Operands)) {
|
|
MCAsmParser &Parser = getParser();
|
|
SMLoc Loc = Parser.getLexer().getLoc();
|
|
MCExpr const *Expr = nullptr;
|
|
bool Error = parseExpression(Expr);
|
|
Expr = HexagonMCExpr::create(Expr, getContext());
|
|
if (!Error)
|
|
Operands.push_back(
|
|
HexagonOperand::CreateImm(getContext(), Expr, Loc, Loc));
|
|
return Error;
|
|
}
|
|
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::Eof:
|
|
case AsmToken::EndOfStatement: {
|
|
Lex();
|
|
return false;
|
|
}
|
|
case AsmToken::LCurly: {
|
|
if (!Operands.empty())
|
|
return true;
|
|
Operands.push_back(HexagonOperand::CreateToken(
|
|
getContext(), Token.getString(), Token.getLoc()));
|
|
Lex();
|
|
return false;
|
|
}
|
|
case AsmToken::RCurly: {
|
|
if (Operands.empty()) {
|
|
Operands.push_back(HexagonOperand::CreateToken(
|
|
getContext(), Token.getString(), Token.getLoc()));
|
|
Lex();
|
|
}
|
|
return false;
|
|
}
|
|
case AsmToken::Comma: {
|
|
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(
|
|
getContext(), Token.getString().substr(0, 1), Token.getLoc()));
|
|
Operands.push_back(HexagonOperand::CreateToken(
|
|
getContext(), Token.getString().substr(1, 1), Token.getLoc()));
|
|
Lex();
|
|
continue;
|
|
}
|
|
case AsmToken::Hash: {
|
|
bool MustNotExtend = false;
|
|
bool ImplicitExpression = implicitExpressionLocation(Operands);
|
|
SMLoc ExprLoc = Lexer.getLoc();
|
|
if (!ImplicitExpression)
|
|
Operands.push_back(HexagonOperand::CreateToken(
|
|
getContext(), Token.getString(), Token.getLoc()));
|
|
Lex();
|
|
bool MustExtend = false;
|
|
bool HiOnly = false;
|
|
bool LoOnly = false;
|
|
if (Lexer.is(AsmToken::Hash)) {
|
|
Lex();
|
|
MustExtend = true;
|
|
} else if (ImplicitExpression)
|
|
MustNotExtend = true;
|
|
AsmToken const &Token = Parser.getTok();
|
|
if (Token.is(AsmToken::Identifier)) {
|
|
StringRef String = Token.getString();
|
|
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 {
|
|
Lex();
|
|
}
|
|
}
|
|
}
|
|
MCExpr const *Expr = nullptr;
|
|
if (parseExpression(Expr))
|
|
return true;
|
|
int64_t Value;
|
|
MCContext &Context = Parser.getContext();
|
|
assert(Expr != nullptr);
|
|
if (Expr->evaluateAsAbsolute(Value)) {
|
|
if (HiOnly)
|
|
Expr = MCBinaryExpr::createLShr(
|
|
Expr, MCConstantExpr::create(16, Context), Context);
|
|
if (HiOnly || LoOnly)
|
|
Expr = MCBinaryExpr::createAnd(
|
|
Expr, MCConstantExpr::create(0xffff, Context), Context);
|
|
} else {
|
|
MCValue Value;
|
|
if (Expr->evaluateAsRelocatable(Value, nullptr, nullptr)) {
|
|
if (!Value.isAbsolute()) {
|
|
switch (Value.getAccessVariant()) {
|
|
case MCSymbolRefExpr::VariantKind::VK_TPREL:
|
|
case MCSymbolRefExpr::VariantKind::VK_DTPREL:
|
|
// Don't lazy extend these expression variants
|
|
MustNotExtend = !MustExtend;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Expr = HexagonMCExpr::create(Expr, Context);
|
|
HexagonMCInstrInfo::setMustNotExtend(*Expr, MustNotExtend);
|
|
HexagonMCInstrInfo::setMustExtend(*Expr, MustExtend);
|
|
std::unique_ptr<HexagonOperand> Operand =
|
|
HexagonOperand::CreateImm(getContext(), Expr, ExprLoc, ExprLoc);
|
|
Operands.push_back(std::move(Operand));
|
|
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);
|
|
}
|
|
|
|
static 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<HexagonOperand *>(&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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
LLVM_DEBUG(dbgs() << "Unmatched Operand:");
|
|
LLVM_DEBUG(Op->dump());
|
|
LLVM_DEBUG(dbgs() << "\n");
|
|
|
|
return Match_InvalidOperand;
|
|
}
|
|
|
|
// FIXME: Calls to OutOfRange shoudl propagate failure up to parseStatement.
|
|
bool HexagonAsmParser::OutOfRange(SMLoc IDLoc, long long Val, long long Max) {
|
|
std::string errStr;
|
|
raw_string_ostream ES(errStr);
|
|
ES << "value " << Val << "(" << format_hex(Val, 0) << ") out of range: ";
|
|
if (Max >= 0)
|
|
ES << "0-" << Max;
|
|
else
|
|
ES << Max << "-" << (-Max - 1);
|
|
return Parser.printError(IDLoc, ES.str());
|
|
}
|
|
|
|
int HexagonAsmParser::processInstruction(MCInst &Inst,
|
|
OperandVector const &Operands,
|
|
SMLoc IDLoc) {
|
|
MCContext &Context = getParser().getContext();
|
|
const MCRegisterInfo *RI = getContext().getRegisterInfo();
|
|
const std::string r = "r";
|
|
const std::string v = "v";
|
|
const std::string Colon = ":";
|
|
using RegPairVals = std::pair<unsigned, unsigned>;
|
|
auto GetRegPair = [this, r](RegPairVals RegPair) {
|
|
const std::string R1 = r + utostr(RegPair.first);
|
|
const std::string R2 = r + utostr(RegPair.second);
|
|
|
|
return std::make_pair(matchRegister(R1), matchRegister(R2));
|
|
};
|
|
auto GetScalarRegs = [RI, GetRegPair](unsigned RegPair) {
|
|
const unsigned Lower = RI->getEncodingValue(RegPair);
|
|
const RegPairVals RegPair_ = std::make_pair(Lower + 1, Lower);
|
|
|
|
return GetRegPair(RegPair_);
|
|
};
|
|
auto GetVecRegs = [GetRegPair](unsigned VecRegPair) {
|
|
const RegPairVals RegPair =
|
|
HexagonMCInstrInfo::GetVecRegPairIndices(VecRegPair);
|
|
|
|
return GetRegPair(RegPair);
|
|
};
|
|
|
|
bool is32bit = false; // used to distinguish between CONST32 and CONST64
|
|
switch (Inst.getOpcode()) {
|
|
default:
|
|
if (HexagonMCInstrInfo::getDesc(MII, Inst).isPseudo()) {
|
|
SMDiagnostic Diag = getSourceManager().GetMessage(
|
|
IDLoc, SourceMgr::DK_Error,
|
|
"Found pseudo instruction with no expansion");
|
|
Diag.print("", errs());
|
|
report_fatal_error("Invalid pseudo instruction");
|
|
}
|
|
break;
|
|
|
|
case Hexagon::J2_trap1:
|
|
if (!getSTI().getFeatureBits()[Hexagon::ArchV65]) {
|
|
MCOperand &Rx = Inst.getOperand(0);
|
|
MCOperand &Ry = Inst.getOperand(1);
|
|
if (Rx.getReg() != Hexagon::R0 || Ry.getReg() != Hexagon::R0) {
|
|
Error(IDLoc, "trap1 can only have register r0 as operand");
|
|
return Match_InvalidOperand;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Hexagon::A2_iconst: {
|
|
Inst.setOpcode(Hexagon::A2_addi);
|
|
MCOperand Reg = Inst.getOperand(0);
|
|
MCOperand S27 = Inst.getOperand(1);
|
|
HexagonMCInstrInfo::setMustNotExtend(*S27.getExpr());
|
|
HexagonMCInstrInfo::setS27_2_reloc(*S27.getExpr());
|
|
Inst.clear();
|
|
Inst.addOperand(Reg);
|
|
Inst.addOperand(MCOperand::createReg(Hexagon::R0));
|
|
Inst.addOperand(S27);
|
|
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(HexagonMCExpr::create(
|
|
MCBinaryExpr::createSub(MO.getExpr(),
|
|
MCConstantExpr::create(1, Context), 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);
|
|
(void)Success;
|
|
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(HexagonMCExpr::create(
|
|
MCBinaryExpr::createSub(MO.getExpr(),
|
|
MCConstantExpr::create(1, Context), Context),
|
|
Context));
|
|
Inst.setOpcode(Hexagon::C2_cmpgtui);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Translate a "$Rdd = $Rss" to "$Rdd = combine($Rs, $Rt)"
|
|
case Hexagon::A2_tfrp: {
|
|
MCOperand &MO = Inst.getOperand(1);
|
|
const std::pair<unsigned, unsigned> RegPair = GetScalarRegs(MO.getReg());
|
|
MO.setReg(RegPair.first);
|
|
Inst.addOperand(MCOperand::createReg(RegPair.second));
|
|
Inst.setOpcode(Hexagon::A2_combinew);
|
|
break;
|
|
}
|
|
|
|
case Hexagon::A2_tfrpt:
|
|
case Hexagon::A2_tfrpf: {
|
|
MCOperand &MO = Inst.getOperand(2);
|
|
const std::pair<unsigned, unsigned> RegPair = GetScalarRegs(MO.getReg());
|
|
MO.setReg(RegPair.first);
|
|
Inst.addOperand(MCOperand::createReg(RegPair.second));
|
|
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);
|
|
const std::pair<unsigned, unsigned> RegPair = GetScalarRegs(MO.getReg());
|
|
MO.setReg(RegPair.first);
|
|
Inst.addOperand(MCOperand::createReg(RegPair.second));
|
|
Inst.setOpcode((Inst.getOpcode() == Hexagon::A2_tfrptnew)
|
|
? Hexagon::C2_ccombinewnewt
|
|
: Hexagon::C2_ccombinewnewf);
|
|
break;
|
|
}
|
|
|
|
// Translate a "$Vdd = $Vss" to "$Vdd = vcombine($Vs, $Vt)"
|
|
case Hexagon::V6_vassignp: {
|
|
MCOperand &MO = Inst.getOperand(1);
|
|
const std::pair<unsigned, unsigned> RegPair = GetVecRegs(MO.getReg());
|
|
MO.setReg(RegPair.first);
|
|
Inst.addOperand(MCOperand::createReg(RegPair.second));
|
|
Inst.setOpcode(Hexagon::V6_vcombine);
|
|
break;
|
|
}
|
|
|
|
// Translate a "$Rx = CONST32(#imm)" to "$Rx = memw(gp+#LABEL) "
|
|
case Hexagon::CONST32:
|
|
is32bit = true;
|
|
LLVM_FALLTHROUGH;
|
|
// Translate a "$Rx:y = CONST64(#imm)" to "$Rx:y = memd(gp+#LABEL) "
|
|
case Hexagon::CONST64:
|
|
// FIXME: need better way to detect AsmStreamer (upstream removed getKind())
|
|
if (!Parser.getStreamer().hasRawTextSupport()) {
|
|
MCELFStreamer *MES = static_cast<MCELFStreamer *>(&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<uint32_t>(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 = nullptr;
|
|
const char *StringEnd = nullptr;
|
|
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(HexagonMCExpr::create(
|
|
MCSymbolRefExpr::create(Sym, getContext()), 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(
|
|
HexagonMCExpr::create(MCConstantExpr::create(sVal, Context), 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)) {
|
|
int s8 = Hi_32(Value);
|
|
if (!isInt<8>(s8))
|
|
OutOfRange(IDLoc, s8, -128);
|
|
MCOperand imm(MCOperand::createExpr(HexagonMCExpr::create(
|
|
MCConstantExpr::create(s8, Context), Context))); // upper 32
|
|
auto Expr = HexagonMCExpr::create(
|
|
MCConstantExpr::create(Lo_32(Value), Context), Context);
|
|
HexagonMCInstrInfo::setMustExtend(
|
|
*Expr, HexagonMCInstrInfo::mustExtend(*MO.getExpr()));
|
|
MCOperand imm2(MCOperand::createExpr(Expr)); // lower 32
|
|
Inst = makeCombineInst(Hexagon::A4_combineii, Rdd, imm, imm2);
|
|
} else {
|
|
MCOperand imm(MCOperand::createExpr(HexagonMCExpr::create(
|
|
MCConstantExpr::create(0, Context), 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 &Rs = Inst.getOperand(2);
|
|
MCOperand &Imm4 = Inst.getOperand(3);
|
|
MCOperand &Imm6 = Inst.getOperand(4);
|
|
Imm6.setExpr(HexagonMCExpr::create(
|
|
MCBinaryExpr::createSub(Imm6.getExpr(),
|
|
MCConstantExpr::create(1, Context), Context),
|
|
Context));
|
|
TmpInst.setOpcode(Hexagon::S2_tableidxh);
|
|
TmpInst.addOperand(Rx);
|
|
TmpInst.addOperand(Rx);
|
|
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 &Rs = Inst.getOperand(2);
|
|
MCOperand &Imm4 = Inst.getOperand(3);
|
|
MCOperand &Imm6 = Inst.getOperand(4);
|
|
Imm6.setExpr(HexagonMCExpr::create(
|
|
MCBinaryExpr::createSub(Imm6.getExpr(),
|
|
MCConstantExpr::create(2, Context), Context),
|
|
Context));
|
|
TmpInst.setOpcode(Hexagon::S2_tableidxw);
|
|
TmpInst.addOperand(Rx);
|
|
TmpInst.addOperand(Rx);
|
|
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 &Rs = Inst.getOperand(2);
|
|
MCOperand &Imm4 = Inst.getOperand(3);
|
|
MCOperand &Imm6 = Inst.getOperand(4);
|
|
Imm6.setExpr(HexagonMCExpr::create(
|
|
MCBinaryExpr::createSub(Imm6.getExpr(),
|
|
MCConstantExpr::create(3, Context), Context),
|
|
Context));
|
|
TmpInst.setOpcode(Hexagon::S2_tableidxd);
|
|
TmpInst.addOperand(Rx);
|
|
TmpInst.addOperand(Rx);
|
|
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;
|
|
MCExpr const &Expr = *Imm.getExpr();
|
|
bool Absolute = Expr.evaluateAsAbsolute(Value);
|
|
if (!Absolute)
|
|
return Match_InvalidOperand;
|
|
if (!HexagonMCInstrInfo::mustExtend(Expr) &&
|
|
((Value <= -256) || Value >= 256))
|
|
return Match_InvalidOperand;
|
|
if (Value < 0 && Value > -256) {
|
|
Imm.setExpr(HexagonMCExpr::create(
|
|
MCConstantExpr::create(Value * -1, Context), Context));
|
|
TmpInst.setOpcode(Hexagon::M2_mpysin);
|
|
} else
|
|
TmpInst.setOpcode(Hexagon::M2_mpysip);
|
|
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);
|
|
if (!Absolute)
|
|
return Match_InvalidOperand;
|
|
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(HexagonMCExpr::create(
|
|
MCBinaryExpr::createSub(Imm.getExpr(),
|
|
MCConstantExpr::create(1, Context), 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);
|
|
if (!Absolute)
|
|
return Match_InvalidOperand;
|
|
if (Value == 0) { // convert to $Rdd = combine ($Rs[0], $Rs[1])
|
|
MCInst TmpInst;
|
|
unsigned int RegPairNum = RI->getEncodingValue(Rss.getReg());
|
|
std::string R1 = r + utostr(RegPairNum + 1);
|
|
StringRef Reg1(R1);
|
|
Rss.setReg(matchRegister(Reg1));
|
|
// Add a new operand for the second register in the pair.
|
|
std::string R2 = r + utostr(RegPairNum);
|
|
StringRef Reg2(R2);
|
|
TmpInst.setOpcode(Hexagon::A2_combinew);
|
|
TmpInst.addOperand(Rdd);
|
|
TmpInst.addOperand(Rss);
|
|
TmpInst.addOperand(MCOperand::createReg(matchRegister(Reg2)));
|
|
Inst = TmpInst;
|
|
} else {
|
|
Imm.setExpr(HexagonMCExpr::create(
|
|
MCBinaryExpr::createSub(Imm.getExpr(),
|
|
MCConstantExpr::create(1, Context), 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 + utostr(RegNum) + Colon + utostr(RegNum - 1);
|
|
StringRef RegPair = Name;
|
|
Rs.setReg(matchRegister(RegPair));
|
|
} else { // raw:lo
|
|
Inst.setOpcode(Hexagon::A4_boundscheck_lo);
|
|
std::string Name = r + utostr(RegNum + 1) + Colon + utostr(RegNum);
|
|
StringRef RegPair = Name;
|
|
Rs.setReg(matchRegister(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 + utostr(RegNum) + Colon + utostr(RegNum - 1);
|
|
StringRef RegPair = Name;
|
|
Rs.setReg(matchRegister(RegPair));
|
|
} else { // Even mapped raw:lo
|
|
Inst.setOpcode(Hexagon::A2_addspl);
|
|
std::string Name = r + utostr(RegNum + 1) + Colon + utostr(RegNum);
|
|
StringRef RegPair = Name;
|
|
Rs.setReg(matchRegister(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 + utostr(RegNum) + Colon + utostr(RegNum - 1);
|
|
StringRef RegPair = Name;
|
|
Rt.setReg(matchRegister(RegPair));
|
|
} else { // Even mapped sat:raw:lo
|
|
Inst.setOpcode(Hexagon::M2_vrcmpys_s1_l);
|
|
std::string Name = r + utostr(RegNum + 1) + Colon + utostr(RegNum);
|
|
StringRef RegPair = Name;
|
|
Rt.setReg(matchRegister(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 + utostr(RegNum) + Colon + utostr(RegNum - 1);
|
|
StringRef RegPair = Name;
|
|
Rt.setReg(matchRegister(RegPair));
|
|
} else { // Even mapped sat:raw:lo
|
|
TmpInst.setOpcode(Hexagon::M2_vrcmpys_acc_s1_l);
|
|
std::string Name = r + utostr(RegNum + 1) + Colon + utostr(RegNum);
|
|
StringRef RegPair = Name;
|
|
Rt.setReg(matchRegister(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 + utostr(RegNum) + Colon + utostr(RegNum - 1);
|
|
StringRef RegPair = Name;
|
|
Rt.setReg(matchRegister(RegPair));
|
|
} else { // Even mapped rnd:sat:raw:lo
|
|
Inst.setOpcode(Hexagon::M2_vrcmpys_s1rp_l);
|
|
std::string Name = r + utostr(RegNum + 1) + Colon + utostr(RegNum);
|
|
StringRef RegPair = Name;
|
|
Rt.setReg(matchRegister(RegPair));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Hexagon::S5_asrhub_rnd_sat_goodsyntax: {
|
|
MCOperand &Imm = Inst.getOperand(2);
|
|
int64_t Value;
|
|
bool Absolute = Imm.getExpr()->evaluateAsAbsolute(Value);
|
|
if (!Absolute)
|
|
return Match_InvalidOperand;
|
|
if (Value == 0)
|
|
Inst.setOpcode(Hexagon::S2_vsathub);
|
|
else {
|
|
Imm.setExpr(HexagonMCExpr::create(
|
|
MCBinaryExpr::createSub(Imm.getExpr(),
|
|
MCConstantExpr::create(1, Context), 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);
|
|
if (!Absolute)
|
|
return Match_InvalidOperand;
|
|
if (Value == 0) {
|
|
MCInst TmpInst;
|
|
unsigned int RegPairNum = RI->getEncodingValue(Rss.getReg());
|
|
std::string R1 = r + utostr(RegPairNum + 1);
|
|
StringRef Reg1(R1);
|
|
Rss.setReg(matchRegister(Reg1));
|
|
// Add a new operand for the second register in the pair.
|
|
std::string R2 = r + utostr(RegPairNum);
|
|
StringRef Reg2(R2);
|
|
TmpInst.setOpcode(Hexagon::A2_combinew);
|
|
TmpInst.addOperand(Rdd);
|
|
TmpInst.addOperand(Rss);
|
|
TmpInst.addOperand(MCOperand::createReg(matchRegister(Reg2)));
|
|
Inst = TmpInst;
|
|
} else {
|
|
Imm.setExpr(HexagonMCExpr::create(
|
|
MCBinaryExpr::createSub(Imm.getExpr(),
|
|
MCConstantExpr::create(1, Context), 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(
|
|
HexagonMCExpr::create(MCConstantExpr::create(-1, Context), Context)));
|
|
TmpInst.addOperand(Rs);
|
|
Inst = TmpInst;
|
|
break;
|
|
}
|
|
case Hexagon::PS_loadrubabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(1).getExpr()))
|
|
Inst.setOpcode(Hexagon::L2_loadrubgp);
|
|
break;
|
|
case Hexagon::PS_loadrbabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(1).getExpr()))
|
|
Inst.setOpcode(Hexagon::L2_loadrbgp);
|
|
break;
|
|
case Hexagon::PS_loadruhabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(1).getExpr()))
|
|
Inst.setOpcode(Hexagon::L2_loadruhgp);
|
|
break;
|
|
case Hexagon::PS_loadrhabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(1).getExpr()))
|
|
Inst.setOpcode(Hexagon::L2_loadrhgp);
|
|
break;
|
|
case Hexagon::PS_loadriabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(1).getExpr()))
|
|
Inst.setOpcode(Hexagon::L2_loadrigp);
|
|
break;
|
|
case Hexagon::PS_loadrdabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(1).getExpr()))
|
|
Inst.setOpcode(Hexagon::L2_loadrdgp);
|
|
break;
|
|
case Hexagon::PS_storerbabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(0).getExpr()))
|
|
Inst.setOpcode(Hexagon::S2_storerbgp);
|
|
break;
|
|
case Hexagon::PS_storerhabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(0).getExpr()))
|
|
Inst.setOpcode(Hexagon::S2_storerhgp);
|
|
break;
|
|
case Hexagon::PS_storerfabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(0).getExpr()))
|
|
Inst.setOpcode(Hexagon::S2_storerfgp);
|
|
break;
|
|
case Hexagon::PS_storeriabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(0).getExpr()))
|
|
Inst.setOpcode(Hexagon::S2_storerigp);
|
|
break;
|
|
case Hexagon::PS_storerdabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(0).getExpr()))
|
|
Inst.setOpcode(Hexagon::S2_storerdgp);
|
|
break;
|
|
case Hexagon::PS_storerbnewabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(0).getExpr()))
|
|
Inst.setOpcode(Hexagon::S2_storerbnewgp);
|
|
break;
|
|
case Hexagon::PS_storerhnewabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(0).getExpr()))
|
|
Inst.setOpcode(Hexagon::S2_storerhnewgp);
|
|
break;
|
|
case Hexagon::PS_storerinewabs:
|
|
if (!HexagonMCInstrInfo::mustExtend(*Inst.getOperand(0).getExpr()))
|
|
Inst.setOpcode(Hexagon::S2_storerinewgp);
|
|
break;
|
|
case Hexagon::A2_zxtb: {
|
|
Inst.setOpcode(Hexagon::A2_andir);
|
|
Inst.addOperand(
|
|
MCOperand::createExpr(MCConstantExpr::create(255, Context)));
|
|
break;
|
|
}
|
|
} // switch
|
|
|
|
return Match_Success;
|
|
}
|
|
|
|
unsigned HexagonAsmParser::matchRegister(StringRef Name) {
|
|
if (unsigned Reg = MatchRegisterName(Name))
|
|
return Reg;
|
|
return MatchRegisterAltName(Name);
|
|
}
|