diff options
author | Eric Astor <epastor@google.com> | 2019-12-30 14:33:56 -0500 |
---|---|---|
committer | Eric Astor <epastor@google.com> | 2019-12-30 14:35:26 -0500 |
commit | 4a7aa252a32a94b1bb61b3dc7f027b4a27ae334f (patch) | |
tree | 3f0579bbc96ff818ae4bc5de945b687f72d2f586 /llvm/lib/Target/X86/AsmParser | |
parent | 7fa0bfe7d580e2b96b8d7f5bd0470287857e84cc (diff) | |
download | bcm5719-llvm-4a7aa252a32a94b1bb61b3dc7f027b4a27ae334f.tar.gz bcm5719-llvm-4a7aa252a32a94b1bb61b3dc7f027b4a27ae334f.zip |
[X86][AsmParser] re-introduce 'offset' operator
Summary:
Amend MS offset operator implementation, to more closely fit with its MS counterpart:
1. InlineAsm: evaluate non-local source entities to their (address) location
2. Provide a mean with which one may acquire the address of an assembly label via MS syntax, rather than yielding a memory reference (i.e. "offset asm_label" and "$asm_label" should be synonymous
3. address PR32530
Based on http://llvm.org/D37461
Fix broken test where the break appears unrelated.
- Set up appropriate memory-input rewrites for variable references.
- Intel-dialect assembly printing now correctly handles addresses by adding "offset".
- Pass offsets as immediate operands (using "r" constraint for offsets of locals).
Reviewed By: rnk
Differential Revision: https://reviews.llvm.org/D71436
Diffstat (limited to 'llvm/lib/Target/X86/AsmParser')
-rw-r--r-- | llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp | 216 | ||||
-rw-r--r-- | llvm/lib/Target/X86/AsmParser/X86Operand.h | 20 |
2 files changed, 149 insertions, 87 deletions
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp index 646b4070556..27c6a5f9142 100644 --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -134,7 +134,6 @@ private: IOK_LENGTH, IOK_SIZE, IOK_TYPE, - IOK_OFFSET }; class InfixCalculator { @@ -326,6 +325,7 @@ private: IES_RSHIFT, IES_PLUS, IES_MINUS, + IES_OFFSET, IES_NOT, IES_MULTIPLY, IES_DIVIDE, @@ -350,16 +350,30 @@ private: 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; } @@ -456,6 +470,7 @@ private: 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) { @@ -500,10 +515,12 @@ private: 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 @@ -556,7 +573,6 @@ private: } PrevState = CurrState; } - bool onRegister(unsigned Reg, StringRef &ErrMsg) { IntelExprState CurrState = State; switch (State) { @@ -604,7 +620,6 @@ private: if (auto *CE = dyn_cast<MCConstantExpr>(SymRef)) return onInteger(CE->getValue(), ErrMsg); PrevState = State; - bool HasSymbol = Sym != nullptr; switch (State) { default: State = IES_ERROR; @@ -614,18 +629,16 @@ private: 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; @@ -738,6 +751,7 @@ private: State = IES_ERROR; break; case IES_INTEGER: + case IES_OFFSET: case IES_REGISTER: case IES_RPAREN: if (BracCount-- != 1) @@ -792,6 +806,7 @@ private: State = IES_ERROR; break; case IES_INTEGER: + case IES_OFFSET: case IES_REGISTER: case IES_RPAREN: State = IES_RPAREN; @@ -799,6 +814,32 @@ private: 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, @@ -830,18 +871,21 @@ private: 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, @@ -1409,26 +1453,44 @@ std::unique_ptr<X86Operand> X86AsmParser::CreateMemForInlineAsm( // 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; } @@ -1471,8 +1533,12 @@ bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) { 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; @@ -1486,9 +1552,6 @@ bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) { } // 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); @@ -1590,9 +1653,9 @@ void X86AsmParser::RewriteIntelExpression(IntelExprStateMachine &SM, 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()); @@ -1607,21 +1670,23 @@ void X86AsmParser::RewriteIntelExpression(IntelExprStateMachine &SM, // 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; @@ -1654,9 +1719,13 @@ bool X86AsmParser::ParseIntelInlineAsmIdentifier(const MCExpr *&Val, 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. @@ -1739,39 +1808,25 @@ bool X86AsmParser::ParseIntelDotOperator(IntelExprStateMachine &SM, SMLoc &End) 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 @@ -1781,7 +1836,6 @@ unsigned X86AsmParser::IdentifyIntelInlineAsmOperator(StringRef Name) { .Cases("TYPE","type",IOK_TYPE) .Cases("SIZE","size",IOK_SIZE) .Cases("LENGTH","length",IOK_LENGTH) - .Cases("OFFSET","offset",IOK_OFFSET) .Default(IOK_INVALID); } @@ -1851,13 +1905,6 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOperand() { 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)) @@ -1905,8 +1952,19 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOperand() { // 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(); diff --git a/llvm/lib/Target/X86/AsmParser/X86Operand.h b/llvm/lib/Target/X86/AsmParser/X86Operand.h index 93626f8254e..36b8bc4e65f 100644 --- a/llvm/lib/Target/X86/AsmParser/X86Operand.h +++ b/llvm/lib/Target/X86/AsmParser/X86Operand.h @@ -53,6 +53,7 @@ struct X86Operand final : public MCParsedAsmOperand { struct ImmOp { const MCExpr *Val; + bool LocalRef; }; struct MemOp { @@ -279,13 +280,9 @@ struct X86Operand final : public MCParsedAsmOperand { return isImmUnsignedi8Value(CE->getValue()); } - bool isOffsetOf() const override { - return OffsetOfLoc.getPointer(); - } + bool isOffsetOfLocal() const override { return isImm() && Imm.LocalRef; } - bool needAddressOf() const override { - return AddressOf; - } + bool needAddressOf() const override { return AddressOf; } bool isCallOperand() const override { return CallOperand; } void setCallOperand(bool IsCallOperand) { CallOperand = IsCallOperand; } @@ -617,9 +614,16 @@ struct X86Operand final : public MCParsedAsmOperand { } static std::unique_ptr<X86Operand> CreateImm(const MCExpr *Val, - SMLoc StartLoc, SMLoc EndLoc) { + SMLoc StartLoc, SMLoc EndLoc, + StringRef SymName = StringRef(), + void *OpDecl = nullptr, + bool GlobalRef = true) { auto Res = std::make_unique<X86Operand>(Immediate, StartLoc, EndLoc); - Res->Imm.Val = Val; + Res->Imm.Val = Val; + Res->Imm.LocalRef = !GlobalRef; + Res->SymName = SymName; + Res->OpDecl = OpDecl; + Res->AddressOf = true; return Res; } |