//===-- ARMAsmParser.cpp - Parse ARM assembly to MCInst instructions ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ARM.h"
#include "ARMSubtarget.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/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/Target/TargetAsmParser.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
using namespace llvm;
namespace {
struct ARMOperand;
// The shift types for register controlled shifts in arm memory addressing
enum ShiftType {
Lsl,
Lsr,
Asr,
Ror,
Rrx
};
class ARMAsmParser : public TargetAsmParser {
MCAsmParser &Parser;
TargetMachine &TM;
private:
MCAsmParser &getParser() const { return Parser; }
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); }
bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
bool MaybeParseRegister(OwningPtr<ARMOperand> &Op, bool ParseWriteBack);
bool ParseRegisterList(OwningPtr<ARMOperand> &Op);
bool ParseMemory(OwningPtr<ARMOperand> &Op);
bool ParseMemoryOffsetReg(bool &Negative,
bool &OffsetRegShifted,
enum ShiftType &ShiftType,
const MCExpr *&ShiftAmount,
const MCExpr *&Offset,
bool &OffsetIsReg,
int &OffsetRegNum,
SMLoc &E);
bool ParseShift(enum ShiftType &St, const MCExpr *&ShiftAmount, SMLoc &E);
bool ParseOperand(OwningPtr<ARMOperand> &Op);
bool ParseDirectiveWord(unsigned Size, SMLoc L);
bool ParseDirectiveThumb(SMLoc L);
bool ParseDirectiveThumbFunc(SMLoc L);
bool ParseDirectiveCode(SMLoc L);
bool ParseDirectiveSyntax(SMLoc L);
bool MatchInstruction(SMLoc IDLoc,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands,
MCInst &Inst) {
if (!MatchInstructionImpl(Operands, Inst))
return false;
// FIXME: We should give nicer diagnostics about the exact failure.
Error(IDLoc, "unrecognized instruction");
return true;
}
/// @name Auto-generated Match Functions
/// {
unsigned ComputeAvailableFeatures(const ARMSubtarget *Subtarget) const;
bool MatchInstructionImpl(const SmallVectorImpl<MCParsedAsmOperand*>
&Operands,
MCInst &Inst);
/// }
public:
ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM)
: TargetAsmParser(T), Parser(_Parser), TM(_TM) {}
virtual bool ParseInstruction(StringRef Name, SMLoc NameLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands);
virtual bool ParseDirective(AsmToken DirectiveID);
};
/// ARMOperand - Instances of this class represent a parsed ARM machine
/// instruction.
struct ARMOperand : public MCParsedAsmOperand {
private:
ARMOperand() {}
public:
enum KindTy {
CondCode,
Immediate,
Memory,
Register,
Token
} Kind;
SMLoc StartLoc, EndLoc;
union {
struct {
ARMCC::CondCodes Val;
} CC;
struct {
const char *Data;
unsigned Length;
} Tok;
struct {
unsigned RegNum;
bool Writeback;
} Reg;
struct {
const MCExpr *Val;
} Imm;
// This is for all forms of ARM address expressions
struct {
unsigned BaseRegNum;
unsigned OffsetRegNum; // used when OffsetIsReg is true
const MCExpr *Offset; // used when OffsetIsReg is false
const MCExpr *ShiftAmount; // used when OffsetRegShifted is true
enum ShiftType ShiftType; // used when OffsetRegShifted is true
unsigned
OffsetRegShifted : 1, // only used when OffsetIsReg is true
Preindexed : 1,
Postindexed : 1,
OffsetIsReg : 1,
Negative : 1, // only used when OffsetIsReg is true
Writeback : 1;
} Mem;
};
ARMOperand(KindTy K, SMLoc S, SMLoc E)
: Kind(K), StartLoc(S), EndLoc(E) {}
ARMOperand(const ARMOperand &o) : MCParsedAsmOperand() {
Kind = o.Kind;
StartLoc