forked from OSchip/llvm-project
[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
This commit is contained in:
parent
7fa0bfe7d5
commit
4a7aa252a3
|
@ -707,8 +707,13 @@ void Sema::FillInlineAsmIdentifierInfo(Expr *Res,
|
|||
if (T->isFunctionType() || T->isDependentType())
|
||||
return Info.setLabel(Res);
|
||||
if (Res->isRValue()) {
|
||||
if (isa<clang::EnumType>(T) && Res->EvaluateAsRValue(Eval, Context))
|
||||
bool IsEnum = isa<clang::EnumType>(T);
|
||||
if (DeclRefExpr *DRE = dyn_cast<clang::DeclRefExpr>(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();
|
||||
|
|
|
@ -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* %{{.*}})
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -75,10 +75,10 @@ public:
|
|||
/// 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(); }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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"
|
||||
|
Loading…
Reference in New Issue