diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 5161b80019180..93faf2d151f96 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -707,8 +707,13 @@ void Sema::FillInlineAsmIdentifierInfo(Expr *Res, if (T->isFunctionType() || T->isDependentType()) return Info.setLabel(Res); if (Res->isRValue()) { - if (isa(T) && Res->EvaluateAsRValue(Eval, Context)) + bool IsEnum = isa(T); + if (DeclRefExpr *DRE = dyn_cast(Res)) + if (DRE->getDecl()->getKind() == Decl::EnumConstant) + IsEnum = true; + if (IsEnum && Res->EvaluateAsRValue(Eval, Context)) return Info.setEnum(Eval.Val.getInt().getSExtValue()); + return Info.setLabel(Res); } unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); diff --git a/clang/test/CodeGen/ms-inline-asm-64.c b/clang/test/CodeGen/ms-inline-asm-64.c index 5b144eb7bb681..ce46b8821dee2 100644 --- a/clang/test/CodeGen/ms-inline-asm-64.c +++ b/clang/test/CodeGen/ms-inline-asm-64.c @@ -12,10 +12,10 @@ void t1() { void t2() { int var = 10; - __asm mov [eax], offset var + __asm mov qword ptr [eax], offset var // CHECK: t2 // CHECK: call void asm sideeffect inteldialect -// CHECK-SAME: mov [eax], $0 +// CHECK-SAME: mov qword ptr [eax], $0 // CHECK-SAME: "r,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) } diff --git a/clang/test/CodeGen/ms-inline-asm.c b/clang/test/CodeGen/ms-inline-asm.c index 0c9b35a64523e..17526f5223113 100644 --- a/clang/test/CodeGen/ms-inline-asm.c +++ b/clang/test/CodeGen/ms-inline-asm.c @@ -190,14 +190,20 @@ void t15() { // CHECK: mov eax, $1 __asm mov eax, offset gvar ; eax = address of gvar // CHECK: mov eax, $2 -// CHECK: "*m,r,r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* @{{.*}}) + __asm mov eax, offset gvar+1 ; eax = 1 + address of gvar +// CHECK: mov eax, $3 + $$1 + __asm mov eax, 1+offset gvar ; eax = 1 + address of gvar +// CHECK: mov eax, $4 + $$1 + __asm mov eax, 1+offset gvar+1 ; eax = 2 + address of gvar +// CHECK: mov eax, $5 + $$2 +// CHECK: "*m,r,i,i,i,i,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}}, i32* @{{.*}}, i32* @{{.*}}, i32* @{{.*}}, i32* @{{.*}}) } void t16() { int var = 10; - __asm mov [eax], offset var + __asm mov dword ptr [eax], offset var // CHECK: t16 -// CHECK: call void asm sideeffect inteldialect "mov [eax], $0", "r,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) +// CHECK: call void asm sideeffect inteldialect "mov dword ptr [eax], $0", "r,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) } void t17() { diff --git a/clang/test/CodeGen/ms-inline-asm.cpp b/clang/test/CodeGen/ms-inline-asm.cpp index 58796ed6378d6..463ff0f6e349a 100644 --- a/clang/test/CodeGen/ms-inline-asm.cpp +++ b/clang/test/CodeGen/ms-inline-asm.cpp @@ -40,7 +40,7 @@ void t2() { // CHECK: call void asm sideeffect inteldialect // CHECK-SAME: mov eax, $0 // CHECK-SAME: mov eax, $1 -// CHECK-SAME: "r,r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3Bar3ptrE) +// CHECK-SAME: "i,i,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE, i32** @_ZN3Foo3Bar3ptrE) } // CHECK-LABEL: define void @_Z2t3v() diff --git a/clang/test/Parser/ms-inline-asm.c b/clang/test/Parser/ms-inline-asm.c index 0170b2b84fa3e..c6af1ea5126b7 100644 --- a/clang/test/Parser/ms-inline-asm.c +++ b/clang/test/Parser/ms-inline-asm.c @@ -57,6 +57,11 @@ void t13() { __asm m{o}v eax, ebx // expected-error {{unknown token in expression}} } +void t14() { + enum { A = 1, B }; + __asm mov eax, offset A // expected-error {{offset operator cannot yet handle constants}} +} + int t_fail() { // expected-note {{to match this}} __asm __asm { // expected-error 3 {{expected}} expected-note {{to match this}} diff --git a/llvm/include/llvm/MC/MCParser/MCParsedAsmOperand.h b/llvm/include/llvm/MC/MCParser/MCParsedAsmOperand.h index c3bb8e52e0951..3dde0b8474a20 100644 --- a/llvm/include/llvm/MC/MCParser/MCParsedAsmOperand.h +++ b/llvm/include/llvm/MC/MCParser/MCParsedAsmOperand.h @@ -75,10 +75,10 @@ class MCParsedAsmOperand { /// Only valid when parsing MS-style inline assembly. virtual bool isCallOperand() const { return false; } - /// isOffsetOf - Do we need to emit code to get the offset of the variable, - /// rather then the value of the variable? Only valid when parsing MS-style - /// inline assembly. - virtual bool isOffsetOf() const { return false; } + /// isOffsetOfLocal - Do we need to emit code to get the offset of the local + /// variable, rather than its value? Only valid when parsing MS-style inline + /// assembly. + virtual bool isOffsetOfLocal() const { return false; } /// getOffsetOfLoc - Get the location of the offset operator. virtual SMLoc getOffsetOfLoc() const { return SMLoc(); } diff --git a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h index e6bc6b9762bcb..6e4821cbc7b9c 100644 --- a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h +++ b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h @@ -66,39 +66,27 @@ struct IntelExpr { 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)); @@ -109,13 +97,14 @@ struct AsmRewrite { 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) diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 7bbd94d07099a..82318d081c9aa 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -5804,10 +5804,6 @@ bool AsmParser::parseMSInlineAsm( 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())) { @@ -5827,18 +5823,27 @@ bool AsmParser::parseMSInlineAsm( 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 @@ -5889,7 +5894,11 @@ bool AsmParser::parseMSInlineAsm( 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(); @@ -5920,9 +5929,32 @@ bool AsmParser::parseMSInlineAsm( 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; diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp index 646b40705560f..27c6a5f91428c 100644 --- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -134,7 +134,6 @@ class X86AsmParser : public MCTargetAsmParser { IOK_LENGTH, IOK_SIZE, IOK_TYPE, - IOK_OFFSET }; class InfixCalculator { @@ -326,6 +325,7 @@ class X86AsmParser : public MCTargetAsmParser { IES_RSHIFT, IES_PLUS, IES_MINUS, + IES_OFFSET, IES_NOT, IES_MULTIPLY, IES_DIVIDE, @@ -350,16 +350,30 @@ class X86AsmParser : public MCTargetAsmParser { 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 @@ class X86AsmParser : public MCTargetAsmParser { 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 @@ class X86AsmParser : public MCTargetAsmParser { 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 @@ class X86AsmParser : public MCTargetAsmParser { } PrevState = CurrState; } - bool onRegister(unsigned Reg, StringRef &ErrMsg) { IntelExprState CurrState = State; switch (State) { @@ -604,7 +620,6 @@ class X86AsmParser : public MCTargetAsmParser { if (auto *CE = dyn_cast(SymRef)) return onInteger(CE->getValue(), ErrMsg); PrevState = State; - bool HasSymbol = Sym != nullptr; switch (State) { default: State = IES_ERROR; @@ -614,18 +629,16 @@ class X86AsmParser : public MCTargetAsmParser { 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 @@ class X86AsmParser : public MCTargetAsmParser { State = IES_ERROR; break; case IES_INTEGER: + case IES_OFFSET: case IES_REGISTER: case IES_RPAREN: if (BracCount-- != 1) @@ -792,6 +806,7 @@ class X86AsmParser : public MCTargetAsmParser { State = IES_ERROR; break; case IES_INTEGER: + case IES_OFFSET: case IES_REGISTER: case IES_RPAREN: State = IES_RPAREN; @@ -799,6 +814,32 @@ class X86AsmParser : public MCTargetAsmParser { 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 @@ class X86AsmParser : public MCTargetAsmParser { std::unique_ptr ParseOperand(); std::unique_ptr ParseATTOperand(); std::unique_ptr ParseIntelOperand(); - std::unique_ptr 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 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 ParseMemOperand(unsigned SegReg, const MCExpr *&Disp, @@ -1409,26 +1453,44 @@ std::unique_ptr 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 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 " 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 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 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 93626f8254e3d..36b8bc4e65f57 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 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(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; } diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp index 8c2b90144b4ab..e9ad7a0476139 100644 --- a/llvm/lib/Target/X86/X86AsmPrinter.cpp +++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -220,8 +220,16 @@ void X86AsmPrinter::PrintOperand(const MachineInstr *MI, unsigned OpNo, case MachineOperand::MO_ConstantPoolIndex: case MachineOperand::MO_GlobalAddress: { - if (IsATT) + switch (MI->getInlineAsmDialect()) { + default: + llvm_unreachable("unknown assembly dialect!"); + case InlineAsm::AD_ATT: O << '$'; + break; + case InlineAsm::AD_Intel: + O << "offset "; + break; + } PrintSymbolOperand(MO, O); break; } diff --git a/llvm/test/CodeGen/X86/ms-inline-asm.ll b/llvm/test/CodeGen/X86/ms-inline-asm.ll index 62525b072bb53..828a76e6ad1f2 100644 --- a/llvm/test/CodeGen/X86/ms-inline-asm.ll +++ b/llvm/test/CodeGen/X86/ms-inline-asm.ll @@ -92,7 +92,7 @@ entry: ; CHECK-LABEL: t30: ; CHECK: {{## InlineAsm Start|#APP}} ; CHECK: .intel_syntax -; CHECK: lea edi, dword ptr [{{_?}}results] +; CHECK: lea edi, dword ptr [offset {{_?}}results] ; CHECK: .att_syntax ; CHECK: {{## InlineAsm End|#NO_APP}} ; CHECK: {{## InlineAsm Start|#APP}} diff --git a/llvm/test/CodeGen/X86/offset-operator.ll b/llvm/test/CodeGen/X86/offset-operator.ll new file mode 100644 index 0000000000000..126e0c4291d74 --- /dev/null +++ b/llvm/test/CodeGen/X86/offset-operator.ll @@ -0,0 +1,15 @@ +; RUN: llc -mtriple=x86_64-unknown-linux-gnu -x86-asm-syntax=intel -relocation-model=static < %s | FileCheck %s + +; Test we are emitting the 'offset' operator upon an immediate reference of a label: +; The emitted 'att-equivalent' of this one is "movl $.L.str, %eax" + +@.str = private unnamed_addr constant [1 x i8] zeroinitializer, align 1 + +define i8* @test_offset_operator() { +; CHECK-LABEL: test_offset_operator: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mov eax, offset .L.str +; CHECK-NEXT: ret +entry: + ret i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str, i64 0, i64 0) +} diff --git a/llvm/test/MC/X86/pr32530.s b/llvm/test/MC/X86/pr32530.s new file mode 100644 index 0000000000000..987f3845b667a --- /dev/null +++ b/llvm/test/MC/X86/pr32530.s @@ -0,0 +1,13 @@ +// RUN: llvm-mc -triple x86_64-unknown-unknown -x86-asm-syntax=intel %s | FileCheck %s + +.text +// CHECK: movq $msg, %rsi +// CHECK: movq $msg+314159, %rax +// CHECK: movq $msg-89793, msg-6535(%rax,%rbx,2) + mov rsi, offset msg + mov rax, offset "msg" + 314159 + mov qword ptr [rax + 2*rbx + offset msg - 6535], offset msg - 89793 +.data +msg: + .ascii "Hello, world!\n" +