int64_t Imm;
StringRef BaseReg;
StringRef IndexReg;
+ StringRef OffsetName;
unsigned Scale;
- IntelExpr(bool needBracs = false) : NeedBracs(needBracs), Imm(0),
- BaseReg(StringRef()), IndexReg(StringRef()),
- Scale(1) {}
- // Compund immediate expression
- IntelExpr(int64_t imm, bool needBracs) : IntelExpr(needBracs) {
- Imm = imm;
- }
- // [Reg + ImmediateExpression]
- // We don't bother to emit an immediate expression evaluated to zero
- IntelExpr(StringRef reg, int64_t imm = 0, unsigned scale = 0,
- bool needBracs = true) :
- IntelExpr(imm, needBracs) {
- IndexReg = reg;
+ IntelExpr()
+ : NeedBracs(false), Imm(0), BaseReg(StringRef()), IndexReg(StringRef()),
+ OffsetName(StringRef()), Scale(1) {}
+ // [BaseReg + IndexReg * ScaleExpression + OFFSET name + ImmediateExpression]
+ IntelExpr(StringRef baseReg, StringRef indexReg, unsigned scale,
+ StringRef offsetName, int64_t imm, bool needBracs)
+ : NeedBracs(needBracs), Imm(imm), BaseReg(baseReg), IndexReg(indexReg),
+ OffsetName(offsetName), Scale(1) {
if (scale)
Scale = scale;
}
- // [BaseReg + IndexReg * ScaleExpression + ImmediateExpression]
- IntelExpr(StringRef baseReg, StringRef indexReg, unsigned scale = 0,
- int64_t imm = 0, bool needBracs = true) :
- IntelExpr(indexReg, imm, scale, needBracs) {
- BaseReg = baseReg;
- }
- bool hasBaseReg() const {
- return BaseReg.size();
- }
- bool hasIndexReg() const {
- return IndexReg.size();
- }
- bool hasRegs() const {
- return hasBaseReg() || hasIndexReg();
- }
+ bool hasBaseReg() const { return !BaseReg.empty(); }
+ bool hasIndexReg() const { return !IndexReg.empty(); }
+ bool hasRegs() const { return hasBaseReg() || hasIndexReg(); }
+ bool hasOffset() const { return !OffsetName.empty(); }
+ // Normally we won't emit immediates unconditionally,
+ // unless we've got no other components
+ bool emitImm() const { return !(hasRegs() || hasOffset()); }
bool isValid() const {
return (Scale == 1) ||
(hasIndexReg() && (Scale == 2 || Scale == 4 || Scale == 8));
AsmRewriteKind Kind;
SMLoc Loc;
unsigned Len;
+ bool Done;
int64_t Val;
StringRef Label;
IntelExpr IntelExp;
public:
AsmRewrite(AsmRewriteKind kind, SMLoc loc, unsigned len = 0, int64_t val = 0)
- : Kind(kind), Loc(loc), Len(len), Val(val) {}
+ : Kind(kind), Loc(loc), Len(len), Done(false), Val(val) {}
AsmRewrite(AsmRewriteKind kind, SMLoc loc, unsigned len, StringRef label)
: AsmRewrite(kind, loc, len) { Label = label; }
AsmRewrite(SMLoc loc, unsigned len, IntelExpr exp)
for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) {
MCParsedAsmOperand &Operand = *Info.ParsedOperands[i];
- // Immediate.
- if (Operand.isImm())
- continue;
-
// Register operand.
if (Operand.isReg() && !Operand.needAddressOf() &&
!getTargetParser().OmitRegisterFromClobberLists(Operand.getReg())) {
if (!OpDecl)
continue;
+ StringRef Constraint = Operand.getConstraint();
+ if (Operand.isImm()) {
+ // Offset as immediate
+ if (Operand.isOffsetOfLocal())
+ Constraint = "r";
+ else
+ Constraint = "i";
+ }
+
bool isOutput = (i == 1) && Desc.mayStore();
SMLoc Start = SMLoc::getFromPointer(SymName.data());
if (isOutput) {
++InputIdx;
OutputDecls.push_back(OpDecl);
OutputDeclsAddressOf.push_back(Operand.needAddressOf());
- OutputConstraints.push_back(("=" + Operand.getConstraint()).str());
+ OutputConstraints.push_back(("=" + Constraint).str());
AsmStrRewrites.emplace_back(AOK_Output, Start, SymName.size());
} else {
InputDecls.push_back(OpDecl);
InputDeclsAddressOf.push_back(Operand.needAddressOf());
- InputConstraints.push_back(Operand.getConstraint().str());
+ InputConstraints.push_back(Constraint.str());
if (Operand.isCallOperand())
AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size());
else
const char *AsmStart = ASMString.begin();
const char *AsmEnd = ASMString.end();
array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort);
- for (const AsmRewrite &AR : AsmStrRewrites) {
+ for (auto it = AsmStrRewrites.begin(); it != AsmStrRewrites.end(); ++it) {
+ const AsmRewrite &AR = *it;
+ // Check if this has already been covered by another rewrite...
+ if (AR.Done)
+ continue;
AsmRewriteKind Kind = AR.Kind;
const char *Loc = AR.Loc.getPointer();
OS << (AR.IntelExp.hasBaseReg() ? " + " : "")
<< AR.IntelExp.IndexReg;
if (AR.IntelExp.Scale > 1)
- OS << " * $$" << AR.IntelExp.Scale;
- if (AR.IntelExp.Imm || !AR.IntelExp.hasRegs())
- OS << (AR.IntelExp.hasRegs() ? " + $$" : "$$") << AR.IntelExp.Imm;
+ OS << " * $$" << AR.IntelExp.Scale;
+ if (AR.IntelExp.hasOffset()) {
+ if (AR.IntelExp.hasRegs())
+ OS << " + ";
+ // Fuse this rewrite with a rewrite of the offset name, if present.
+ StringRef OffsetName = AR.IntelExp.OffsetName;
+ SMLoc OffsetLoc = SMLoc::getFromPointer(AR.IntelExp.OffsetName.data());
+ size_t OffsetLen = OffsetName.size();
+ auto rewrite_it = std::find_if(
+ it, AsmStrRewrites.end(), [&](const AsmRewrite &FusingAR) {
+ return FusingAR.Loc == OffsetLoc && FusingAR.Len == OffsetLen &&
+ (FusingAR.Kind == AOK_Input ||
+ FusingAR.Kind == AOK_CallInput);
+ });
+ if (rewrite_it == AsmStrRewrites.end()) {
+ OS << "offset " << OffsetName;
+ } else if (rewrite_it->Kind == AOK_CallInput) {
+ OS << "${" << InputIdx++ << ":P}";
+ rewrite_it->Done = true;
+ } else {
+ OS << '$' << InputIdx++;
+ rewrite_it->Done = true;
+ }
+ }
+ if (AR.IntelExp.Imm || AR.IntelExp.emitImm())
+ OS << (AR.IntelExp.emitImm() ? "$$" : " + $$") << AR.IntelExp.Imm;
if (AR.IntelExp.NeedBracs)
OS << "]";
break;
IOK_LENGTH,
IOK_SIZE,
IOK_TYPE,
- IOK_OFFSET
};
class InfixCalculator {
IES_RSHIFT,
IES_PLUS,
IES_MINUS,
+ IES_OFFSET,
IES_NOT,
IES_MULTIPLY,
IES_DIVIDE,
InlineAsmIdentifierInfo Info;
short BracCount;
bool MemExpr;
+ bool OffsetOperator;
+ SMLoc OffsetOperatorLoc;
+
+ bool setSymRef(const MCExpr *Val, StringRef ID, StringRef &ErrMsg) {
+ if (Sym) {
+ ErrMsg = "cannot use more than one symbol in memory operand";
+ return true;
+ }
+ Sym = Val;
+ SymName = ID;
+ return false;
+ }
public:
IntelExprStateMachine()
: State(IES_INIT), PrevState(IES_ERROR), BaseReg(0), IndexReg(0),
TmpReg(0), Scale(0), Imm(0), Sym(nullptr), BracCount(0),
- MemExpr(false) {}
+ MemExpr(false), OffsetOperator(false) {}
void addImm(int64_t imm) { Imm += imm; }
short getBracCount() { return BracCount; }
bool isMemExpr() { return MemExpr; }
+ bool isOffsetOperator() { return OffsetOperator; }
+ SMLoc getOffsetLoc() { return OffsetOperatorLoc; }
unsigned getBaseReg() { return BaseReg; }
unsigned getIndexReg() { return IndexReg; }
unsigned getScale() { return Scale; }
case IES_INTEGER:
case IES_RPAREN:
case IES_REGISTER:
+ case IES_OFFSET:
State = IES_PLUS;
IC.pushOperator(IC_PLUS);
if (CurrState == IES_REGISTER && PrevState != IES_MULTIPLY) {
case IES_INTEGER:
case IES_REGISTER:
case IES_INIT:
+ case IES_OFFSET:
State = IES_MINUS;
// push minus operator if it is not a negate operator
if (CurrState == IES_REGISTER || CurrState == IES_RPAREN ||
- CurrState == IES_INTEGER || CurrState == IES_RBRAC)
+ CurrState == IES_INTEGER || CurrState == IES_RBRAC ||
+ CurrState == IES_OFFSET)
IC.pushOperator(IC_MINUS);
else if (PrevState == IES_REGISTER && CurrState == IES_MULTIPLY) {
// We have negate operator for Scale: it's illegal
}
PrevState = CurrState;
}
-
bool onRegister(unsigned Reg, StringRef &ErrMsg) {
IntelExprState CurrState = State;
switch (State) {
if (auto *CE = dyn_cast<MCConstantExpr>(SymRef))
return onInteger(CE->getValue(), ErrMsg);
PrevState = State;
- bool HasSymbol = Sym != nullptr;
switch (State) {
default:
State = IES_ERROR;
case IES_NOT:
case IES_INIT:
case IES_LBRAC:
+ if (setSymRef(SymRef, SymRefName, ErrMsg))
+ return true;
MemExpr = true;
State = IES_INTEGER;
- Sym = SymRef;
- SymName = SymRefName;
IC.pushOperand(IC_IMM);
if (ParsingInlineAsm)
Info = IDInfo;
break;
}
- if (HasSymbol)
- ErrMsg = "cannot use more than one symbol in memory operand";
- return HasSymbol;
+ return false;
}
bool onInteger(int64_t TmpInt, StringRef &ErrMsg) {
IntelExprState CurrState = State;
State = IES_ERROR;
break;
case IES_INTEGER:
+ case IES_OFFSET:
case IES_REGISTER:
case IES_RPAREN:
if (BracCount-- != 1)
State = IES_ERROR;
break;
case IES_INTEGER:
+ case IES_OFFSET:
case IES_REGISTER:
case IES_RPAREN:
State = IES_RPAREN;
break;
}
}
+ bool onOffset(const MCExpr *Val, SMLoc OffsetLoc, StringRef ID,
+ const InlineAsmIdentifierInfo &IDInfo, bool ParsingInlineAsm,
+ StringRef &ErrMsg) {
+ PrevState = State;
+ switch (State) {
+ default:
+ ErrMsg = "unexpected offset operator expression";
+ return true;
+ case IES_PLUS:
+ case IES_INIT:
+ case IES_LBRAC:
+ if (setSymRef(Val, ID, ErrMsg))
+ return true;
+ OffsetOperator = true;
+ OffsetOperatorLoc = OffsetLoc;
+ State = IES_OFFSET;
+ // As we cannot yet resolve the actual value (offset), we retain
+ // the requested semantics by pushing a '0' to the operands stack
+ IC.pushOperand(IC_IMM);
+ if (ParsingInlineAsm) {
+ Info = IDInfo;
+ }
+ break;
+ }
+ return false;
+ }
};
bool Error(SMLoc L, const Twine &Msg, SMRange Range = None,
std::unique_ptr<X86Operand> ParseOperand();
std::unique_ptr<X86Operand> ParseATTOperand();
std::unique_ptr<X86Operand> ParseIntelOperand();
- std::unique_ptr<X86Operand> ParseIntelOffsetOfOperator();
+ bool ParseIntelOffsetOperator(const MCExpr *&Val, StringRef &ID,
+ InlineAsmIdentifierInfo &Info, SMLoc &End);
bool ParseIntelDotOperator(IntelExprStateMachine &SM, SMLoc &End);
unsigned IdentifyIntelInlineAsmOperator(StringRef Name);
unsigned ParseIntelInlineAsmOperator(unsigned OpKind);
std::unique_ptr<X86Operand> ParseRoundingModeOp(SMLoc Start);
- bool ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM);
+ bool ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM,
+ bool &ParseError, SMLoc &End);
void RewriteIntelExpression(IntelExprStateMachine &SM, SMLoc Start,
SMLoc End);
bool ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End);
bool ParseIntelInlineAsmIdentifier(const MCExpr *&Val, StringRef &Identifier,
InlineAsmIdentifierInfo &Info,
- bool IsUnevaluatedOperand, SMLoc &End);
+ bool IsUnevaluatedOperand, SMLoc &End,
+ bool IsParsingOffsetOperator = false);
std::unique_ptr<X86Operand> ParseMemOperand(unsigned SegReg,
const MCExpr *&Disp,
// Some binary bitwise operators have a named synonymous
// Query a candidate string for being such a named operator
// and if so - invoke the appropriate handler
-bool X86AsmParser::ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM) {
+bool X86AsmParser::ParseIntelNamedOperator(StringRef Name,
+ IntelExprStateMachine &SM,
+ bool &ParseError, SMLoc &End) {
// A named operator should be either lower or upper case, but not a mix
if (Name.compare(Name.lower()) && Name.compare(Name.upper()))
return false;
- if (Name.equals_lower("not"))
+ if (Name.equals_lower("not")) {
SM.onNot();
- else if (Name.equals_lower("or"))
+ } else if (Name.equals_lower("or")) {
SM.onOr();
- else if (Name.equals_lower("shl"))
+ } else if (Name.equals_lower("shl")) {
SM.onLShift();
- else if (Name.equals_lower("shr"))
+ } else if (Name.equals_lower("shr")) {
SM.onRShift();
- else if (Name.equals_lower("xor"))
+ } else if (Name.equals_lower("xor")) {
SM.onXor();
- else if (Name.equals_lower("and"))
+ } else if (Name.equals_lower("and")) {
SM.onAnd();
- else if (Name.equals_lower("mod"))
+ } else if (Name.equals_lower("mod")) {
SM.onMod();
- else
+ } else if (Name.equals_lower("offset")) {
+ SMLoc OffsetLoc = getTok().getLoc();
+ const MCExpr *Val = nullptr;
+ StringRef ID;
+ InlineAsmIdentifierInfo Info;
+ ParseError = ParseIntelOffsetOperator(Val, ID, Info, End);
+ if (ParseError)
+ return true;
+ StringRef ErrMsg;
+ ParseError =
+ SM.onOffset(Val, OffsetLoc, ID, Info, isParsingInlineAsm(), ErrMsg);
+ if (ParseError)
+ return Error(SMLoc::getFromPointer(Name.data()), ErrMsg);
+ } else {
return false;
+ }
+ if (!Name.equals_lower("offset"))
+ End = consumeToken();
return true;
}
break;
}
// Operator synonymous ("not", "or" etc.)
- if ((UpdateLocLex = ParseIntelNamedOperator(Identifier, SM)))
+ bool ParseError = false;
+ if (ParseIntelNamedOperator(Identifier, SM, ParseError, End)) {
+ if (ParseError)
+ return true;
break;
+ }
// Symbol reference, when parsing assembly content
InlineAsmIdentifierInfo Info;
const MCExpr *Val;
}
// MS InlineAsm operators (TYPE/LENGTH/SIZE)
if (unsigned OpKind = IdentifyIntelInlineAsmOperator(Identifier)) {
- if (OpKind == IOK_OFFSET)
- return Error(IdentLoc, "Dealing OFFSET operator as part of"
- "a compound immediate expression is yet to be supported");
if (int64_t Val = ParseIntelInlineAsmOperator(OpKind)) {
if (SM.onInteger(Val, ErrMsg))
return Error(IdentLoc, ErrMsg);
SMLoc Loc = Start;
unsigned ExprLen = End.getPointer() - Start.getPointer();
// Skip everything before a symbol displacement (if we have one)
- if (SM.getSym()) {
+ if (SM.getSym() && !SM.isOffsetOperator()) {
StringRef SymName = SM.getSymName();
- if (unsigned Len = SymName.data() - Start.getPointer())
+ if (unsigned Len = SymName.data() - Start.getPointer())
InstInfo->AsmRewrites->emplace_back(AOK_Skip, Start, Len);
Loc = SMLoc::getFromPointer(SymName.data() + SymName.size());
ExprLen = End.getPointer() - (SymName.data() + SymName.size());
// Build an Intel Expression rewrite
StringRef BaseRegStr;
StringRef IndexRegStr;
+ StringRef OffsetNameStr;
if (SM.getBaseReg())
BaseRegStr = X86IntelInstPrinter::getRegisterName(SM.getBaseReg());
if (SM.getIndexReg())
IndexRegStr = X86IntelInstPrinter::getRegisterName(SM.getIndexReg());
+ if (SM.isOffsetOperator())
+ OffsetNameStr = SM.getSymName();
// Emit it
- IntelExpr Expr(BaseRegStr, IndexRegStr, SM.getScale(), SM.getImm(), SM.isMemExpr());
+ IntelExpr Expr(BaseRegStr, IndexRegStr, SM.getScale(), OffsetNameStr,
+ SM.getImm(), SM.isMemExpr());
InstInfo->AsmRewrites->emplace_back(Loc, ExprLen, Expr);
}
// Inline assembly may use variable names with namespace alias qualifiers.
-bool X86AsmParser::ParseIntelInlineAsmIdentifier(const MCExpr *&Val,
- StringRef &Identifier,
- InlineAsmIdentifierInfo &Info,
- bool IsUnevaluatedOperand,
- SMLoc &End) {
+bool X86AsmParser::ParseIntelInlineAsmIdentifier(
+ const MCExpr *&Val, StringRef &Identifier, InlineAsmIdentifierInfo &Info,
+ bool IsUnevaluatedOperand, SMLoc &End, bool IsParsingOffsetOperator) {
MCAsmParser &Parser = getParser();
assert(isParsingInlineAsm() && "Expected to be parsing inline assembly.");
Val = nullptr;
SemaCallback->LookupInlineAsmLabel(Identifier, getSourceManager(),
Loc, false);
assert(InternalName.size() && "We should have an internal name here.");
- // Push a rewrite for replacing the identifier name with the internal name.
- InstInfo->AsmRewrites->emplace_back(AOK_Label, Loc, Identifier.size(),
- InternalName);
+ // Push a rewrite for replacing the identifier name with the internal name,
+ // unless we are parsing the operand of an offset operator
+ if (!IsParsingOffsetOperator)
+ InstInfo->AsmRewrites->emplace_back(AOK_Label, Loc, Identifier.size(),
+ InternalName);
+ else
+ Identifier = InternalName;
} else if (Info.isKind(InlineAsmIdentifierInfo::IK_EnumVal))
return false;
// Create the symbol reference.
return false;
}
-/// Parse the 'offset' operator. This operator is used to specify the
-/// location rather then the content of a variable.
-std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOffsetOfOperator() {
- MCAsmParser &Parser = getParser();
- const AsmToken &Tok = Parser.getTok();
- SMLoc OffsetOfLoc = Tok.getLoc();
- Parser.Lex(); // Eat offset.
-
- const MCExpr *Val;
- InlineAsmIdentifierInfo Info;
- SMLoc Start = Tok.getLoc(), End;
- StringRef Identifier = Tok.getString();
- if (ParseIntelInlineAsmIdentifier(Val, Identifier, Info,
- /*Unevaluated=*/false, End))
- return nullptr;
-
- void *Decl = nullptr;
- // FIXME: MS evaluates "offset <Constant>" to the underlying integral
- if (Info.isKind(InlineAsmIdentifierInfo::IK_EnumVal))
- return ErrorOperand(Start, "offset operator cannot yet handle constants");
- else if (Info.isKind(InlineAsmIdentifierInfo::IK_Var))
- Decl = Info.Var.Decl;
- // Don't emit the offset operator.
- InstInfo->AsmRewrites->emplace_back(AOK_Skip, OffsetOfLoc, 7);
-
- // The offset operator will have an 'r' constraint, thus we need to create
- // register operand to ensure proper matching. Just pick a GPR based on
- // the size of a pointer.
- bool Parse32 = is32BitMode() || Code16GCC;
- unsigned RegNo = is64BitMode() ? X86::RBX : (Parse32 ? X86::EBX : X86::BX);
-
- return X86Operand::CreateReg(RegNo, Start, End, /*GetAddress=*/true,
- OffsetOfLoc, Identifier, Decl);
+/// Parse the 'offset' operator.
+/// This operator is used to specify the location of a given operand
+bool X86AsmParser::ParseIntelOffsetOperator(const MCExpr *&Val, StringRef &ID,
+ InlineAsmIdentifierInfo &Info,
+ SMLoc &End) {
+ // Eat offset, mark start of identifier.
+ SMLoc Start = Lex().getLoc();
+ ID = getTok().getString();
+ if (!isParsingInlineAsm()) {
+ if ((getTok().isNot(AsmToken::Identifier) &&
+ getTok().isNot(AsmToken::String)) ||
+ getParser().parsePrimaryExpr(Val, End))
+ return Error(Start, "unexpected token!");
+ } else if (ParseIntelInlineAsmIdentifier(Val, ID, Info, false, End, true)) {
+ return Error(Start, "unable to lookup expression");
+ } else if (Info.isKind(InlineAsmIdentifierInfo::IK_EnumVal)) {
+ return Error(Start, "offset operator cannot yet handle constants");
+ }
+ return false;
}
// Query a candidate string for being an Intel assembly operator
.Cases("TYPE","type",IOK_TYPE)
.Cases("SIZE","size",IOK_SIZE)
.Cases("LENGTH","length",IOK_LENGTH)
- .Cases("OFFSET","offset",IOK_OFFSET)
.Default(IOK_INVALID);
}
const AsmToken &Tok = Parser.getTok();
SMLoc Start, End;
- // FIXME: Offset operator
- // Should be handled as part of immediate expression, as other operators
- // Currently, only supported as a stand-alone operand
- if (isParsingInlineAsm())
- if (IdentifyIntelInlineAsmOperator(Tok.getString()) == IOK_OFFSET)
- return ParseIntelOffsetOfOperator();
-
// Parse optional Size directive.
unsigned Size;
if (ParseIntelMemoryOperandSize(Size))
// RegNo != 0 specifies a valid segment register,
// and we are parsing a segment override
- if (!SM.isMemExpr() && !RegNo)
+ if (!SM.isMemExpr() && !RegNo) {
+ if (isParsingInlineAsm() && SM.isOffsetOperator()) {
+ const InlineAsmIdentifierInfo Info = SM.getIdentifierInfo();
+ if (Info.isKind(InlineAsmIdentifierInfo::IK_Var)) {
+ // Disp includes the address of a variable; make sure this is recorded
+ // for later handling.
+ return X86Operand::CreateImm(Disp, Start, End, SM.getSymName(),
+ Info.Var.Decl, Info.Var.IsGlobalLV);
+ }
+ }
+
return X86Operand::CreateImm(Disp, Start, End);
+ }
StringRef ErrMsg;
unsigned BaseReg = SM.getBaseReg();