Index: include/llvm/MC/MCParser/MCAsmParser.h =================================================================== --- include/llvm/MC/MCParser/MCAsmParser.h +++ include/llvm/MC/MCParser/MCAsmParser.h @@ -34,19 +34,60 @@ class MCTargetAsmParser; class SourceMgr; -class InlineAsmIdentifierInfo { -public: - void *OpDecl; - bool IsVarDecl; - unsigned Length, Size, Type; - - void clear() { - OpDecl = nullptr; - IsVarDecl = false; - Length = 1; - Size = 0; - Type = 0; +struct InlineAsmIdentifierInfo { + enum IdKind { + Invalid, // Initial state. Unexpected after a successful parsing. + LabelKind, // Function/Label reference. + EnumValKind, // Value of enumration type. + VarKind // Variable. + }; + // Represents an Enum value + struct EnumIdentifier { + int64_t EnumVal; + }; + // Represents a label/function reference + struct LabelIdentifier { + void *Decl; + }; + // Represents a variable + struct VariableIdentifier { + void *Decl; + bool IsGlobalLV; + unsigned Length; + unsigned Size; + unsigned Type; + }; + // An InlineAsm identifier can only be one of those + union { + EnumIdentifier Enum; + LabelIdentifier Label; + VariableIdentifier Var; + }; + bool isKind(IdKind kind) const { return Kind == kind; } + // Initializers + void setEnum(int64_t enumVal) { + assert(isKind(Invalid) && "should be initialized only once"); + Kind = EnumValKind; + Enum.EnumVal = enumVal; + } + void setLabel(void *decl) { + assert(isKind(Invalid) && "should be initialized only once"); + Kind = LabelKind; + Label.Decl = decl; } + void setVar(void *decl, bool isGlobalLV, unsigned size, unsigned type) { + assert(isKind(Invalid) && "should be initialized only once"); + Kind = VarKind; + Var.Decl = decl; + Var.IsGlobalLV = isGlobalLV; + Var.Size = size; + Var.Type = type; + Var.Length = size / type; + } + InlineAsmIdentifierInfo() : Kind(Invalid) {} +private: + // Discrimint using the current kind + IdKind Kind; }; /// \brief Generic Sema callback for assembly parser. @@ -54,9 +95,9 @@ public: virtual ~MCAsmParserSemaCallback(); - virtual void *LookupInlineAsmIdentifier(StringRef &LineBuf, - InlineAsmIdentifierInfo &Info, - bool IsUnevaluatedContext) = 0; + virtual void LookupInlineAsmIdentifier(StringRef &LineBuf, + InlineAsmIdentifierInfo &Info, + bool IsUnevaluatedContext) = 0; virtual StringRef LookupInlineAsmLabel(StringRef Identifier, SourceMgr &SM, SMLoc Location, bool Create) = 0; virtual bool LookupInlineAsmField(StringRef Base, StringRef Member, Index: lib/Target/X86/AsmParser/X86AsmParser.cpp =================================================================== --- lib/Target/X86/AsmParser/X86AsmParser.cpp +++ lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -339,9 +339,7 @@ IntelExprStateMachine() : State(IES_INIT), PrevState(IES_ERROR), BaseReg(0), IndexReg(0), TmpReg(0), Scale(1), Imm(0), Sym(nullptr), BracCount(0), - MemExpr(false) { - Info.clear(); - } + MemExpr(false) {} void addImm(int64_t imm) { Imm += imm; } short getBracCount() { return BracCount; } @@ -580,7 +578,21 @@ return false; } bool onIdentifierExpr(const MCExpr *SymRef, StringRef SymRefName, - StringRef &ErrMsg) { + const InlineAsmIdentifierInfo &IDInfo, + bool ParsingInlineAsm, StringRef &ErrMsg) { + // InlineAsm: Treat an enum value as an integer + if (ParsingInlineAsm) + if (IDInfo.isKind(InlineAsmIdentifierInfo::EnumValKind)) { + if (onInteger(IDInfo.Enum.EnumVal, ErrMsg)) + return true; + return false; + } + // Treat a symbolic constant like an integer + if (auto *CE = dyn_cast(SymRef)) { + if (onInteger(CE->getValue(), ErrMsg)) + return true; + return false; + } PrevState = State; bool HasSymbol = Sym != nullptr; switch (State) { @@ -592,11 +604,13 @@ case IES_NOT: case IES_INIT: case IES_LBRAC: - MemExpr = !(SymRef->getKind() == MCExpr::Constant); + MemExpr = true; State = IES_INTEGER; Sym = SymRef; SymName = SymRefName; IC.pushOperand(IC_IMM); + if (ParsingInlineAsm) + Info = IDInfo; break; } if (HasSymbol) @@ -826,7 +840,7 @@ CreateMemForInlineAsm(unsigned SegReg, const MCExpr *Disp, unsigned BaseReg, unsigned IndexReg, unsigned Scale, SMLoc Start, SMLoc End, unsigned Size, StringRef Identifier, - InlineAsmIdentifierInfo &Info); + const InlineAsmIdentifierInfo &Info); bool parseDirectiveEven(SMLoc L); bool ParseDirectiveWord(unsigned Size, SMLoc L); @@ -1258,41 +1272,46 @@ std::unique_ptr X86AsmParser::CreateMemForInlineAsm( unsigned SegReg, const MCExpr *Disp, unsigned BaseReg, unsigned IndexReg, unsigned Scale, SMLoc Start, SMLoc End, unsigned Size, StringRef Identifier, - InlineAsmIdentifierInfo &Info) { + const InlineAsmIdentifierInfo &Info) { // If we found a decl other than a VarDecl, then assume it is a FuncDecl or // some other label reference. - if (isa(Disp) && Info.OpDecl && !Info.IsVarDecl) { + if (Info.isKind(InlineAsmIdentifierInfo::LabelKind)) { // Insert an explicit size if the user didn't have one. if (!Size) { Size = getPointerWidth(); InstInfo->AsmRewrites->emplace_back(AOK_SizeDirective, Start, /*Len=*/0, Size); } - // Create an absolute memory reference in order to match against // instructions taking a PC relative operand. return X86Operand::CreateMem(getPointerWidth(), Disp, Start, End, Size, - Identifier, Info.OpDecl); + Identifier, Info.Label.Decl); } - - // We either have a direct symbol reference, or an offset from a symbol. The // parser always puts the symbol on the LHS, so look there for size // calculation purposes. unsigned FrontendSize = 0; - const MCBinaryExpr *BinOp = dyn_cast(Disp); - bool IsSymRef = - isa(BinOp ? BinOp->getLHS() : Disp); - if (IsSymRef && !Size && Info.Type) - FrontendSize = Info.Type * 8; // Size is in terms of bits in this context. - - // When parsing inline assembly we set the base register to a non-zero value + void *Decl = nullptr; + bool IsGlobalLV = false; + if (Info.isKind(InlineAsmIdentifierInfo::VarKind)) { + // Size is in terms of bits in this context. + FrontendSize = Info.Var.Type * 8; + Decl = Info.Var.Decl; + IsGlobalLV = Info.Var.IsGlobalLV; + } + // It is widely common for MS InlineAsm to use a global variable and one/two + // registers in a mmory expression, and though unaccessible via rip/eip. + if (IsGlobalLV && (BaseReg || IndexReg)) { + return X86Operand::CreateMem(getPointerWidth(), Disp, Start, End); + // Otherwise, we set the base register to a non-zero value // if we don't know the actual value at this time. This is necessary to // get the matching correct in some cases. - BaseReg = BaseReg ? BaseReg : 1; - return X86Operand::CreateMem(getPointerWidth(), SegReg, Disp, BaseReg, - IndexReg, Scale, Start, End, Size, Identifier, - Info.OpDecl, FrontendSize); + } else { + BaseReg = BaseReg ? BaseReg : 1; + return X86Operand::CreateMem(getPointerWidth(), SegReg, Disp, BaseReg, + IndexReg, Scale, Start, End, Size, Identifier, + Decl, FrontendSize); + } } // Some binary bitwise operators have a named synonymous @@ -1348,44 +1367,53 @@ break; case AsmToken::String: case AsmToken::Identifier: { - // This could be a register or a symbolic displacement. - unsigned TmpReg; - const MCExpr *Val; SMLoc IdentLoc = Tok.getLoc(); StringRef Identifier = Tok.getString(); UpdateLocLex = false; - if (TK != AsmToken::String && !ParseRegister(TmpReg, IdentLoc, End)) { - if (SM.onRegister(TmpReg, ErrMsg)) + // Register + unsigned Reg; + if (Tok.isNot(AsmToken::String) && !ParseRegister(Reg, IdentLoc, End)) { + if (SM.onRegister(Reg, ErrMsg)) return Error(Tok.getLoc(), ErrMsg); - } else if (ParseIntelNamedOperator(Identifier, SM)) { - UpdateLocLex = true; - } else if (!isParsingInlineAsm()) { - if (getParser().parsePrimaryExpr(Val, End)) + break; + } + // Operator synonymous ("not", "or" etc.) + if ((UpdateLocLex = ParseIntelNamedOperator(Identifier, SM))) + break; + // Symbol reference, when parsing assembly content + InlineAsmIdentifierInfo Info; + const MCExpr *Val; + if (!isParsingInlineAsm()) { + if (getParser().parsePrimaryExpr(Val, End)) { return Error(Tok.getLoc(), "Unexpected identifier!"); - if (auto *CE = dyn_cast(Val)) { - if (SM.onInteger(CE->getValue(), ErrMsg)) - return Error(IdentLoc, ErrMsg); - } else if (SM.onIdentifierExpr(Val, Identifier, ErrMsg)) + } else if (SM.onIdentifierExpr(Val, Identifier, Info, false, ErrMsg)) { return Error(IdentLoc, ErrMsg); - } else if (unsigned OpKind = IdentifyIntelInlineAsmOperator(Identifier)) { + } else + break; + } + // 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"); - int64_t Val = ParseIntelInlineAsmOperator(OpKind); - if (!Val) + if (int64_t Val = ParseIntelInlineAsmOperator(OpKind)) { + if (SM.onInteger(Val, ErrMsg)) + return Error(IdentLoc, ErrMsg); + } else return true; - if (SM.onInteger(Val, ErrMsg)) - return Error(IdentLoc, ErrMsg); - } else if (Identifier.count('.') && PrevTK == AsmToken::RBrac) { - if (ParseIntelDotOperator(SM, End)) - return true; - } else if (ParseIntelInlineAsmIdentifier(Val, Identifier, - SM.getIdentifierInfo(), - /*Unevaluated=*/false, End)) { + break; + } + // MS Dot Operator expression + if (Identifier.count('.') && PrevTK == AsmToken::RBrac) { + if (ParseIntelDotOperator(SM, End)) + return true; + break; + } + // MS InlineAsm identifier + if (ParseIntelInlineAsmIdentifier(Val, Identifier, Info, false, End)) return true; - } else if (SM.onIdentifierExpr(Val, Identifier, ErrMsg)) { + else if (SM.onIdentifierExpr(Val, Identifier, Info, true, ErrMsg)) return Error(IdentLoc, ErrMsg); - } break; } case AsmToken::Integer: { @@ -1405,7 +1433,9 @@ if (IDVal == "b" && Sym->isUndefined()) return Error(Loc, "invalid reference to undefined symbol"); StringRef Identifier = Sym->getName(); - if (SM.onIdentifierExpr(Val, Identifier, ErrMsg)) + InlineAsmIdentifierInfo Info; + if (SM.onIdentifierExpr(Val, Identifier, Info, + isParsingInlineAsm(), ErrMsg)) return Error(Loc, ErrMsg); End = consumeToken(); } else { @@ -1500,8 +1530,7 @@ Val = nullptr; StringRef LineBuf(Identifier.data()); - void *Result = - SemaCallback->LookupInlineAsmIdentifier(LineBuf, Info, IsUnevaluatedOperand); + SemaCallback->LookupInlineAsmIdentifier(LineBuf, Info, IsUnevaluatedOperand); const AsmToken &Tok = Parser.getTok(); SMLoc Loc = Tok.getLoc(); @@ -1517,12 +1546,13 @@ // The frontend should end parsing on an assembler token boundary, unless it // failed parsing. - assert((End.getPointer() == EndPtr || !Result) && - "frontend claimed part of a token?"); + assert((End.getPointer() == EndPtr || + Info.isKind(InlineAsmIdentifierInfo::Invalid)) && + "frontend claimed part of a token?"); // If the identifier lookup was unsuccessful, assume that we are dealing with // a label. - if (!Result) { + if (Info.isKind(InlineAsmIdentifierInfo::Invalid)) { StringRef InternalName = SemaCallback->LookupInlineAsmLabel(Identifier, getSourceManager(), Loc, false); @@ -1530,8 +1560,8 @@ // Push a rewrite for replacing the identifier name with the internal name. InstInfo->AsmRewrites->emplace_back(AOK_Label, Loc, Identifier.size(), InternalName); - } - + } else if (Info.isKind(InlineAsmIdentifierInfo::EnumValKind)) + return false; // Create the symbol reference. MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; @@ -1625,6 +1655,12 @@ /*Unevaluated=*/false, End)) return nullptr; + void *Decl = nullptr; + // FIXME: MS evaluates "offset " to the underlying integral + if (Info.isKind(InlineAsmIdentifierInfo::EnumValKind)) + return ErrorOperand(Start, "offset operator cannot yet handle constants"); + else if (Info.isKind(InlineAsmIdentifierInfo::VarKind)) + Decl = Info.Var.Decl; // Don't emit the offset operator. InstInfo->AsmRewrites->emplace_back(AOK_Skip, OffsetOfLoc, 7); @@ -1635,7 +1671,7 @@ unsigned RegNo = is64BitMode() ? X86::RBX : (Parse32 ? X86::EBX : X86::BX); return X86Operand::CreateReg(RegNo, Start, End, /*GetAddress=*/true, - OffsetOfLoc, Identifier, Info.OpDecl); + OffsetOfLoc, Identifier, Decl); } // Query a candidate string for being an Intel assembly operator @@ -1668,7 +1704,7 @@ /*Unevaluated=*/true, End)) return 0; - if (!Info.OpDecl) { + if (!Info.isKind(InlineAsmIdentifierInfo::VarKind)) { Error(Start, "unable to lookup expression"); return 0; } @@ -1676,9 +1712,9 @@ unsigned CVal = 0; switch(OpKind) { default: llvm_unreachable("Unexpected operand kind!"); - case IOK_LENGTH: CVal = Info.Length; break; - case IOK_SIZE: CVal = Info.Size; break; - case IOK_TYPE: CVal = Info.Type; break; + case IOK_LENGTH: CVal = Info.Var.Length; break; + case IOK_SIZE: CVal = Info.Var.Size; break; + case IOK_TYPE: CVal = Info.Var.Type; break; } return CVal;