diff options
| author | Coby Tayree <coby.tayree@intel.com> | 2017-09-29 07:02:46 +0000 |
|---|---|---|
| committer | Coby Tayree <coby.tayree@intel.com> | 2017-09-29 07:02:46 +0000 |
| commit | c3d24118e8232864e347f1db3420e8ed89c61219 (patch) | |
| tree | 8c6387be8ac05bb5497f5a9d14301eaa5254e650 /llvm/lib/Target | |
| parent | c2ec6ce65c50bb9ad2ed0d1a6e7ae7c2c35c34fd (diff) | |
| download | bcm5719-llvm-c3d24118e8232864e347f1db3420e8ed89c61219.tar.gz bcm5719-llvm-c3d24118e8232864e347f1db3420e8ed89c61219.zip | |
[X86][MS-InlineAsm] Extended support for variables / identifiers on memory / immediate expressions
Allow the proper recognition of Enum values and global variables inside ms inline-asm memory / immediate expressions, as they require some additional overhead and treated incorrect if doesn't early recognized.
supersedes D33278, D35774
Differential Revision: https://reviews.llvm.org/D37412
llvm-svn: 314493
Diffstat (limited to 'llvm/lib/Target')
| -rw-r--r-- | llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp | 150 |
1 files changed, 90 insertions, 60 deletions
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp index bd176bac4c4..112af623b4a 100644 --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -339,9 +339,7 @@ private: 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,15 @@ private: 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::IK_EnumVal)) + return onInteger(IDInfo.Enum.EnumVal, ErrMsg); + // Treat a symbolic constant like an integer + if (auto *CE = dyn_cast<MCConstantExpr>(SymRef)) + return onInteger(CE->getValue(), ErrMsg); PrevState = State; bool HasSymbol = Sym != nullptr; switch (State) { @@ -592,11 +598,13 @@ private: 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) @@ -1261,38 +1269,43 @@ std::unique_ptr<X86Operand> X86AsmParser::CreateMemForInlineAsm( 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<MCSymbolRefExpr>(Disp) && Info.OpDecl && !Info.IsVarDecl) { + if (Info.isKind(InlineAsmIdentifierInfo::IK_Label)) { // 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<MCBinaryExpr>(Disp); - bool IsSymRef = - isa<MCSymbolRefExpr>(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::IK_Var)) { + // 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 +1361,53 @@ bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) { 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<MCConstantExpr>(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 +1427,9 @@ bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) { 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 +1524,7 @@ bool X86AsmParser::ParseIntelInlineAsmIdentifier(const MCExpr *&Val, 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 +1540,13 @@ bool X86AsmParser::ParseIntelInlineAsmIdentifier(const MCExpr *&Val, // 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::IK_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::IK_Invalid)) { StringRef InternalName = SemaCallback->LookupInlineAsmLabel(Identifier, getSourceManager(), Loc, false); @@ -1530,8 +1554,8 @@ bool X86AsmParser::ParseIntelInlineAsmIdentifier(const MCExpr *&Val, // 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::IK_EnumVal)) + return false; // Create the symbol reference. MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; @@ -1625,6 +1649,12 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOffsetOfOperator() { /*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); @@ -1635,7 +1665,7 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOffsetOfOperator() { 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 +1698,7 @@ unsigned X86AsmParser::ParseIntelInlineAsmOperator(unsigned OpKind) { /*Unevaluated=*/true, End)) return 0; - if (!Info.OpDecl) { + if (!Info.isKind(InlineAsmIdentifierInfo::IK_Var)) { Error(Start, "unable to lookup expression"); return 0; } @@ -1676,9 +1706,9 @@ unsigned X86AsmParser::ParseIntelInlineAsmOperator(unsigned OpKind) { 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; |

