Skip to content

Commit

Permalink
[ms-inline asm] Add support for operands that include both a symbol a…
Browse files Browse the repository at this point in the history
…nd an

immediate displacement.  Specifically, add support for generating the proper IR.
We've been able to parse this for some time now.  Test case to be added on the
clang side.
Part of rdar://13453209

llvm-svn: 179393
  • Loading branch information
Chad Rosier committed Apr 12, 2013
1 parent 1b58f33 commit 175d0ae
Showing 1 changed file with 103 additions and 41 deletions.
144 changes: 103 additions & 41 deletions llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ class X86AsmParser : public MCTargetAsmParser {
StringRef &Identifier);
X86Operand *ParseMemOperand(unsigned SegReg, SMLoc StartLoc);

X86Operand *CreateMemForInlineAsm(const MCExpr *Disp, SMLoc Start, SMLoc End,
X86Operand *CreateMemForInlineAsm(unsigned SegReg, const MCExpr *Disp,
unsigned BaseReg, unsigned IndexReg,
unsigned Scale, SMLoc Start, SMLoc End,
SMLoc SizeDirLoc, unsigned Size,
StringRef SymName);

Expand Down Expand Up @@ -851,15 +853,20 @@ class IntelBracExprStateMachine {
IntelBracExprState State;
unsigned BaseReg, IndexReg, TmpReg, Scale;
int64_t Disp;
const MCExpr *Sym;
StringRef SymName;
InfixCalculator IC;
public:
IntelBracExprStateMachine(MCAsmParser &parser, int64_t disp) :
State(IBES_PLUS), BaseReg(0), IndexReg(0), TmpReg(0), Scale(1), Disp(disp){}
State(IBES_PLUS), BaseReg(0), IndexReg(0), TmpReg(0), Scale(1), Disp(disp),
Sym(0) {}

unsigned getBaseReg() { return BaseReg; }
unsigned getIndexReg() { return IndexReg; }
unsigned getScale() { return Scale; }
int64_t getDisp() { return Disp + IC.execute(); }
const MCExpr *getSym() { return Sym; }
StringRef getSymName() { return SymName; }
int64_t getImmDisp() { return Disp + IC.execute(); }
bool isValidEndState() { return State == IBES_RBRAC; }

void onPlus() {
Expand Down Expand Up @@ -936,14 +943,16 @@ class IntelBracExprStateMachine {
break;
}
}
void onDispExpr() {
void onDispExpr(const MCExpr *SymRef, StringRef SymRefName) {
switch (State) {
default:
State = IBES_ERROR;
break;
case IBES_PLUS:
case IBES_MINUS:
State = IBES_INTEGER;
Sym = SymRef;
SymName = SymRefName;
IC.pushOperand(IC_IMM);
break;
}
Expand Down Expand Up @@ -1070,45 +1079,47 @@ class IntelBracExprStateMachine {
}
};

X86Operand *X86AsmParser::CreateMemForInlineAsm(const MCExpr *Disp, SMLoc Start,
SMLoc End, SMLoc SizeDirLoc,
unsigned Size, StringRef SymName) {
X86Operand *
X86AsmParser::CreateMemForInlineAsm(unsigned SegReg, const MCExpr *Disp,
unsigned BaseReg, unsigned IndexReg,
unsigned Scale, SMLoc Start, SMLoc End,
SMLoc SizeDirLoc, unsigned Size,
StringRef SymName) {
bool NeedSizeDir = false;
bool IsVarDecl = false;

if (const MCSymbolRefExpr *SymRef = dyn_cast<MCSymbolRefExpr>(Disp)) {
const MCSymbol &Sym = SymRef->getSymbol();
// FIXME: The SemaLookup will fail if the name is anything other then an
// identifier.
// FIXME: Pass a valid SMLoc.
bool IsVarDecl = false;
unsigned tLength, tSize, tType;
SemaCallback->LookupInlineAsmIdentifier(Sym.getName(), NULL, tLength, tSize,
tType, IsVarDecl);
if (!Size) {
Size = tType * 8; // Size is in terms of bits in this context.
NeedSizeDir = Size > 0;
}
}

// If this is not a VarDecl then assume it is a FuncDecl or some other label
// reference. We need an 'r' constraint here, so we need to create register
// operand to ensure proper matching. Just pick a GPR based on the size of
// a pointer.
if (!IsVarDecl) {
unsigned RegNo = is64BitMode() ? X86::RBX : X86::EBX;
return X86Operand::CreateReg(RegNo, Start, End, /*AddressOf=*/true, SMLoc(),
SymName);
// If this is not a VarDecl then assume it is a FuncDecl or some other label
// reference. We need an 'r' constraint here, so we need to create register
// operand to ensure proper matching. Just pick a GPR based on the size of
// a pointer.
if (!IsVarDecl) {
unsigned RegNo = is64BitMode() ? X86::RBX : X86::EBX;
return X86Operand::CreateReg(RegNo, Start, End, /*AddressOf=*/true,
SMLoc(), SymName);
}
}

if (NeedSizeDir)
InstInfo->AsmRewrites->push_back(AsmRewrite(AOK_SizeDirective, SizeDirLoc,
/*Len*/0, Size));

// When parsing inline assembly we set the base register to a non-zero value
// as we don't know the actual value at this time. This is necessary to
// if we don't know the actual value at this time. This is necessary to
// get the matching correct in some cases.
return X86Operand::CreateMem(/*SegReg*/0, Disp, /*BaseReg*/1, /*IndexReg*/0,
/*Scale*/1, Start, End, Size, SymName);
BaseReg = BaseReg ? BaseReg : 1;
return X86Operand::CreateMem(SegReg, Disp, BaseReg, IndexReg, Scale, Start,
End, Size, SymName);
}

X86Operand *X86AsmParser::ParseIntelBracExpression(unsigned SegReg,
Expand All @@ -1118,12 +1129,12 @@ X86Operand *X86AsmParser::ParseIntelBracExpression(unsigned SegReg,
const AsmToken &Tok = Parser.getTok();
SMLoc Start = Tok.getLoc(), End = Tok.getEndLoc();

// Eat '['
if (getLexer().isNot(AsmToken::LBrac))
return ErrorOperand(Start, "Expected '[' token!");
Parser.Lex();
Parser.Lex(); // Eat '['

unsigned TmpReg = 0;
SMLoc StartInBrac = Tok.getLoc();

// Try to handle '[' 'Symbol' ']'
if (getLexer().is(AsmToken::Identifier)) {
Expand All @@ -1148,8 +1159,9 @@ X86Operand *X86AsmParser::ParseIntelBracExpression(unsigned SegReg,
Parser.Lex(); // Eat ']'
if (!isParsingInlineAsm())
return X86Operand::CreateMem(Disp, Start, End, Size);
return CreateMemForInlineAsm(Disp, Start, End, SizeDirLoc, Size,
Identifier);
return CreateMemForInlineAsm(/*SegReg=*/0, Disp, /*BaseReg=*/0,
/*IndexReg=*/0, /*Scale*/1, Start, End,
SizeDirLoc, Size, Identifier);
}
}

Expand All @@ -1164,7 +1176,6 @@ X86Operand *X86AsmParser::ParseIntelBracExpression(unsigned SegReg,
if (TmpReg)
SM.onRegister(TmpReg);

const MCExpr *Disp = 0;
while (!Done) {
bool UpdateLocLex = true;

Expand All @@ -1182,14 +1193,17 @@ X86Operand *X86AsmParser::ParseIntelBracExpression(unsigned SegReg,
return ErrorOperand(Tok.getLoc(), "Unexpected token!");
}
case AsmToken::Identifier: {
// This could be a register or a displacement expression.
SMLoc Loc = Tok.getLoc();
if(!ParseRegister(TmpReg, Loc, End)) {
// This could be a register or a symbolic displacement.
unsigned TmpReg;
const MCExpr *Disp = 0;
AsmToken IdentTok = Parser.getTok();
SMLoc IdentLoc = IdentTok.getLoc();
if(!ParseRegister(TmpReg, IdentLoc, End)) {
SM.onRegister(TmpReg);
UpdateLocLex = false;
break;
} else if (!getParser().parsePrimaryExpr(Disp, End)) {
SM.onDispExpr();
SM.onDispExpr(Disp, IdentTok.getString());
UpdateLocLex = false;
break;
}
Expand All @@ -1215,14 +1229,58 @@ X86Operand *X86AsmParser::ParseIntelBracExpression(unsigned SegReg,
Parser.Lex(); // Consume the token.
}
}
if (isParsingInlineAsm() && Disp && isa<MCSymbolRefExpr>(Disp)) {
// Remove the '[' and ']' from the IR string.
InstInfo->AsmRewrites->push_back(AsmRewrite(AOK_Skip, Start, 1));
InstInfo->AsmRewrites->push_back(AsmRewrite(AOK_Skip, End, 1));
}

if (!Disp)
Disp = MCConstantExpr::Create(SM.getDisp(), getContext());
const MCExpr *Disp;
if (const MCExpr *Sym = SM.getSym()) {
Disp = Sym;

if (isParsingInlineAsm()) {
// Remove the '[' and ']' from the IR string.
InstInfo->AsmRewrites->push_back(AsmRewrite(AOK_Skip, Start, 1));
InstInfo->AsmRewrites->push_back(AsmRewrite(AOK_Skip, End, 1));

// If ImmDisp is non-zero, then we parsed a displacement before the
// bracketed expression (i.e., ImmDisp [ BaseReg + Scale*IndexReg + Disp ])
uint64_t FinalImmDisp = SM.getImmDisp();
if (ImmDisp && ImmDisp != FinalImmDisp) {
// If ImmDisp doesn't match the displacement computed by the state machine
// then we have an additional displacement in the bracketed expression.

} else if (FinalImmDisp) {
// We have a symbolic and an immediate displacement, but no displacement
// before the bracketed expression.

// Put the immediate displacement before the bracketed expression.
InstInfo->AsmRewrites->push_back(AsmRewrite(AOK_Imm, Start, 0,
FinalImmDisp));
}
// Remove all the ImmPrefix rewrites within the brackets.
for (SmallVectorImpl<AsmRewrite>::iterator
I = InstInfo->AsmRewrites->begin(),
E = InstInfo->AsmRewrites->end(); I != E; ++I) {
if ((*I).Loc.getPointer() < StartInBrac.getPointer())
continue;
if ((*I).Kind == AOK_ImmPrefix)
(*I).Kind = AOK_Delete;
}
StringRef SymName = SM.getSymName();
const char *SymLocPtr = SymName.data();
// Skip everything before the symbol.
if (unsigned Len = SymLocPtr - StartInBrac.getPointer()) {
assert(Len > 0 && "Expected a non-negative length.");
InstInfo->AsmRewrites->push_back(AsmRewrite(AOK_Skip, StartInBrac, Len));
}
// Skip everything after the symbol.
if (unsigned Len = End.getPointer() - (SymLocPtr + SymName.size())) {
SMLoc Loc = SMLoc::getFromPointer(SymLocPtr + SymName.size());
assert(Len > 0 && "Expected a non-negative length.");
InstInfo->AsmRewrites->push_back(AsmRewrite(AOK_Skip, Loc, Len));
}
}
} else {
// An immediate displacement only.
Disp = MCConstantExpr::Create(SM.getImmDisp(), getContext());
}

// Parse the dot operator (e.g., [ebx].foo.bar).
if (Tok.getString().startswith(".")) {
Expand All @@ -1238,6 +1296,11 @@ X86Operand *X86AsmParser::ParseIntelBracExpression(unsigned SegReg,

int BaseReg = SM.getBaseReg();
int IndexReg = SM.getIndexReg();
int Scale = SM.getScale();

if (isParsingInlineAsm())
return CreateMemForInlineAsm(SegReg, Disp, BaseReg, IndexReg, Scale, Start,
End, SizeDirLoc, Size, SM.getSymName());

// handle [-42]
if (!BaseReg && !IndexReg) {
Expand All @@ -1246,8 +1309,6 @@ X86Operand *X86AsmParser::ParseIntelBracExpression(unsigned SegReg,
else
return X86Operand::CreateMem(SegReg, Disp, 0, 0, 1, Start, End, Size);
}

int Scale = SM.getScale();
return X86Operand::CreateMem(SegReg, Disp, BaseReg, IndexReg, Scale, Start,
End, Size);
}
Expand Down Expand Up @@ -1345,7 +1406,8 @@ X86Operand *X86AsmParser::ParseIntelMemOperand(unsigned SegReg,
if (X86Operand *Err = ParseIntelVarWithQualifier(Disp, Identifier))
return Err;

return CreateMemForInlineAsm(Disp, Start, End, Start, Size, Identifier);
return CreateMemForInlineAsm(/*SegReg=*/0, Disp, /*BaseReg=*/0,/*IndexReg=*/0,
/*Scale=*/1, Start, End, Start, Size,Identifier);
}

/// Parse the '.' operator.
Expand Down

0 comments on commit 175d0ae

Please sign in to comment.