summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
authorCoby Tayree <coby.tayree@intel.com>2017-09-29 07:02:46 +0000
committerCoby Tayree <coby.tayree@intel.com>2017-09-29 07:02:46 +0000
commitc3d24118e8232864e347f1db3420e8ed89c61219 (patch)
tree8c6387be8ac05bb5497f5a9d14301eaa5254e650 /llvm/lib/Target
parentc2ec6ce65c50bb9ad2ed0d1a6e7ae7c2c35c34fd (diff)
downloadbcm5719-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.cpp150
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;
OpenPOWER on IntegriCloud