summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChad Rosier <mcrosier@apple.com>2013-04-05 16:28:55 +0000
committerChad Rosier <mcrosier@apple.com>2013-04-05 16:28:55 +0000
commite112453fc39b97147ea3f23bf0b1973cd9f739b1 (patch)
treeccfecfa94d21a0e1ccbce64492c4f7328b2c4fb9
parent9463c0f3da8e325fea96e36540da18cadaa3f303 (diff)
downloadllvm-e112453fc39b97147ea3f23bf0b1973cd9f739b1.tar.gz
llvm-e112453fc39b97147ea3f23bf0b1973cd9f739b1.tar.bz2
llvm-e112453fc39b97147ea3f23bf0b1973cd9f739b1.tar.xz
[ms-inline asm] Add support for numeric displacement expressions in bracketed
memory operands. Essentially, this layers an infix calculator on top of the parsing state machine. The scale on the index register is still expected to be an immediate __asm mov eax, [eax + ebx*4] and will not work with more complex expressions. For example, __asm mov eax, [eax + ebx*(2*2)] The plus and minus binary operators assume the numeric value of a register is zero so as to not change the displacement. Register operands should never be an operand for a multiply or divide operation; the scale*indexreg expression is always replaced with a zero on the operand stack to prevent such a case. rdar://13521380 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@178881 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/X86/AsmParser/X86AsmParser.cpp310
-rw-r--r--test/MC/X86/intel-syntax.s39
2 files changed, 284 insertions, 65 deletions
diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp
index e4623228b3..e9fc0d7ed1 100644
--- a/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -676,41 +676,180 @@ static unsigned getIntelMemOperandSize(StringRef OpStr) {
return Size;
}
+enum InfixCalculatorTok {
+ IC_PLUS = 0,
+ IC_MINUS,
+ IC_MULTIPLY,
+ IC_DIVIDE,
+ IC_RPAREN,
+ IC_LPAREN,
+ IC_IMM,
+ IC_REGISTER
+};
+static const char OpPrecedence[] = {
+ 0, // IC_PLUS
+ 0, // IC_MINUS
+ 1, // IC_MULTIPLY
+ 1, // IC_DIVIDE
+ 2, // IC_RPAREN
+ 3, // IC_LPAREN
+ 0, // IC_IMM
+ 0 // IC_REGISTER
+};
+
+class InfixCalculator {
+ typedef std::pair< InfixCalculatorTok, int64_t > ICToken;
+ SmallVector<InfixCalculatorTok, 4> InfixOperatorStack;
+ SmallVector<ICToken, 4> PostfixStack;
+
+public:
+ int64_t popOperand() {
+ assert (!PostfixStack.empty() && "Poped an empty stack!");
+ ICToken Op = PostfixStack.pop_back_val();
+ assert ((Op.first == IC_IMM || Op.first == IC_REGISTER)
+ && "Expected and immediate or register!");
+ return Op.second;
+ }
+ void pushOperand(InfixCalculatorTok Op, int64_t Val = 0) {
+ assert ((Op == IC_IMM || Op == IC_REGISTER) &&
+ "Unexpected operand!");
+ PostfixStack.push_back(std::make_pair(Op, Val));
+ }
+
+ void popOperator() { InfixOperatorStack.pop_back_val(); }
+ void pushOperator(InfixCalculatorTok Op) {
+ // Push the new operator if the stack is empty.
+ if (InfixOperatorStack.empty()) {
+ InfixOperatorStack.push_back(Op);
+ return;
+ }
+
+ // Push the new operator if it has a higher precedence than the operator on
+ // the top of the stack or the operator on the top of the stack is a left
+ // parentheses.
+ unsigned Idx = InfixOperatorStack.size() - 1;
+ InfixCalculatorTok StackOp = InfixOperatorStack[Idx];
+ if (OpPrecedence[Op] > OpPrecedence[StackOp] || StackOp == IC_LPAREN) {
+ InfixOperatorStack.push_back(Op);
+ return;
+ }
+
+ // The operator on the top of the stack has higher precedence than the
+ // new operator.
+ unsigned ParenCount = 0;
+ while (1) {
+ // Nothing to process.
+ if (InfixOperatorStack.empty())
+ break;
+
+ Idx = InfixOperatorStack.size() - 1;
+ StackOp = InfixOperatorStack[Idx];
+ if (!(OpPrecedence[StackOp] >= OpPrecedence[Op] || ParenCount))
+ break;
+
+ // If we have an even parentheses count and we see a left parentheses,
+ // then stop processing.
+ if (!ParenCount && StackOp == IC_LPAREN)
+ break;
+
+ if (StackOp == IC_RPAREN) {
+ ++ParenCount;
+ InfixOperatorStack.pop_back_val();
+ } else if (StackOp == IC_LPAREN) {
+ --ParenCount;
+ InfixOperatorStack.pop_back_val();
+ } else {
+ InfixOperatorStack.pop_back_val();
+ PostfixStack.push_back(std::make_pair(StackOp, 0));
+ }
+ }
+ // Push the new operator.
+ InfixOperatorStack.push_back(Op);
+ }
+ int64_t execute() {
+ // Push any remaining operators onto the postfix stack.
+ while (!InfixOperatorStack.empty()) {
+ InfixCalculatorTok StackOp = InfixOperatorStack.pop_back_val();
+ if (StackOp != IC_LPAREN && StackOp != IC_RPAREN)
+ PostfixStack.push_back(std::make_pair(StackOp, 0));
+ }
+
+ if (PostfixStack.empty())
+ return 0;
+
+ SmallVector<ICToken, 16> OperandStack;
+ for (unsigned i = 0, e = PostfixStack.size(); i != e; ++i) {
+ ICToken Op = PostfixStack[i];
+ if (Op.first == IC_IMM || Op.first == IC_REGISTER) {
+ OperandStack.push_back(Op);
+ } else {
+ assert (OperandStack.size() > 1 && "Too few operands.");
+ int64_t Val;
+ ICToken Op2 = OperandStack.pop_back_val();
+ ICToken Op1 = OperandStack.pop_back_val();
+ switch (Op.first) {
+ default:
+ report_fatal_error("Unexpected operator!");
+ break;
+ case IC_PLUS:
+ Val = Op1.second + Op2.second;
+ OperandStack.push_back(std::make_pair(IC_IMM, Val));
+ break;
+ case IC_MINUS:
+ Val = Op1.second - Op2.second;
+ OperandStack.push_back(std::make_pair(IC_IMM, Val));
+ break;
+ case IC_MULTIPLY:
+ assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
+ "Multiply operation with an immediate and a register!");
+ Val = Op1.second * Op2.second;
+ OperandStack.push_back(std::make_pair(IC_IMM, Val));
+ break;
+ case IC_DIVIDE:
+ assert (Op1.first == IC_IMM && Op2.first == IC_IMM &&
+ "Divide operation with an immediate and a register!");
+ assert (Op2.second != 0 && "Division by zero!");
+ Val = Op1.second / Op2.second;
+ OperandStack.push_back(std::make_pair(IC_IMM, Val));
+ break;
+ }
+ }
+ }
+ assert (OperandStack.size() == 1 && "Expected a single result.");
+ return OperandStack.pop_back_val().second;
+ }
+};
+
enum IntelBracExprState {
- IBES_START,
+ IBES_PLUS,
+ IBES_MINUS,
+ IBES_MULTIPLY,
+ IBES_DIVIDE,
IBES_LBRAC,
IBES_RBRAC,
+ IBES_LPAREN,
+ IBES_RPAREN,
IBES_REGISTER,
IBES_REGISTER_STAR,
- IBES_REGISTER_STAR_INTEGER,
IBES_INTEGER,
IBES_INTEGER_STAR,
- IBES_INDEX_REGISTER,
IBES_IDENTIFIER,
- IBES_DISP_EXPR,
- IBES_MINUS,
IBES_ERROR
};
class IntelBracExprStateMachine {
IntelBracExprState State;
- unsigned BaseReg, IndexReg, Scale;
+ unsigned BaseReg, IndexReg, TmpReg, Scale;
int64_t Disp;
-
- unsigned TmpReg;
- int64_t TmpInteger;
-
- bool isPlus;
-
+ InfixCalculator IC;
public:
IntelBracExprStateMachine(MCAsmParser &parser, int64_t disp) :
- State(IBES_START), BaseReg(0), IndexReg(0), Scale(1), Disp(disp),
- TmpReg(0), TmpInteger(0), isPlus(true) {}
+ State(IBES_PLUS), BaseReg(0), IndexReg(0), TmpReg(0), Scale(1), Disp(disp){}
unsigned getBaseReg() { return BaseReg; }
unsigned getIndexReg() { return IndexReg; }
unsigned getScale() { return Scale; }
- int64_t getDisp() { return Disp; }
+ int64_t getDisp() { return Disp + IC.execute(); }
bool isValidEndState() { return State == IBES_RBRAC; }
void onPlus() {
@@ -719,14 +858,12 @@ public:
State = IBES_ERROR;
break;
case IBES_INTEGER:
- State = IBES_START;
- if (isPlus)
- Disp += TmpInteger;
- else
- Disp -= TmpInteger;
+ case IBES_RPAREN:
+ State = IBES_PLUS;
+ IC.pushOperator(IC_PLUS);
break;
case IBES_REGISTER:
- State = IBES_START;
+ State = IBES_PLUS;
// If we already have a BaseReg, then assume this is the IndexReg with a
// scale of 1.
if (!BaseReg) {
@@ -736,30 +873,25 @@ public:
IndexReg = TmpReg;
Scale = 1;
}
- break;
- case IBES_INDEX_REGISTER:
- State = IBES_START;
+ IC.pushOperator(IC_PLUS);
break;
}
- isPlus = true;
}
void onMinus() {
switch (State) {
default:
State = IBES_ERROR;
break;
- case IBES_START:
- State = IBES_MINUS;
- break;
+ case IBES_PLUS:
+ case IBES_LPAREN:
+ IC.pushOperand(IC_IMM);
case IBES_INTEGER:
- State = IBES_START;
- if (isPlus)
- Disp += TmpInteger;
- else
- Disp -= TmpInteger;
+ case IBES_RPAREN:
+ State = IBES_MINUS;
+ IC.pushOperator(IC_MINUS);
break;
case IBES_REGISTER:
- State = IBES_START;
+ State = IBES_MINUS;
// If we already have a BaseReg, then assume this is the IndexReg with a
// scale of 1.
if (!BaseReg) {
@@ -769,27 +901,28 @@ public:
IndexReg = TmpReg;
Scale = 1;
}
- break;
- case IBES_INDEX_REGISTER:
- State = IBES_START;
+ IC.pushOperator(IC_MINUS);
break;
}
- isPlus = false;
}
void onRegister(unsigned Reg) {
switch (State) {
default:
State = IBES_ERROR;
break;
- case IBES_START:
+ case IBES_PLUS:
+ case IBES_LPAREN:
State = IBES_REGISTER;
TmpReg = Reg;
+ IC.pushOperand(IC_REGISTER);
break;
case IBES_INTEGER_STAR:
assert (!IndexReg && "IndexReg already set!");
- State = IBES_INDEX_REGISTER;
+ State = IBES_INTEGER;
IndexReg = Reg;
- Scale = TmpInteger;
+ Scale = IC.popOperand();
+ IC.pushOperand(IC_IMM);
+ IC.popOperator();
break;
}
}
@@ -798,8 +931,10 @@ public:
default:
State = IBES_ERROR;
break;
- case IBES_START:
- State = IBES_DISP_EXPR;
+ case IBES_PLUS:
+ case IBES_MINUS:
+ State = IBES_INTEGER;
+ IC.pushOperand(IC_IMM);
break;
}
}
@@ -808,19 +943,21 @@ public:
default:
State = IBES_ERROR;
break;
- case IBES_START:
- State = IBES_INTEGER;
- TmpInteger = TmpInt;
- break;
+ case IBES_PLUS:
case IBES_MINUS:
+ case IBES_MULTIPLY:
+ case IBES_DIVIDE:
+ case IBES_LPAREN:
+ case IBES_INTEGER_STAR:
State = IBES_INTEGER;
- TmpInteger = TmpInt;
+ IC.pushOperand(IC_IMM, TmpInt);
break;
case IBES_REGISTER_STAR:
assert (!IndexReg && "IndexReg already set!");
- State = IBES_INDEX_REGISTER;
+ State = IBES_INTEGER;
IndexReg = TmpReg;
Scale = TmpInt;
+ IC.popOperator();
break;
}
}
@@ -831,9 +968,26 @@ public:
break;
case IBES_INTEGER:
State = IBES_INTEGER_STAR;
+ IC.pushOperator(IC_MULTIPLY);
break;
case IBES_REGISTER:
State = IBES_REGISTER_STAR;
+ IC.pushOperator(IC_MULTIPLY);
+ break;
+ case IBES_RPAREN:
+ State = IBES_MULTIPLY;
+ IC.pushOperator(IC_MULTIPLY);
+ break;
+ }
+ }
+ void onDivide() {
+ switch (State) {
+ default:
+ State = IBES_ERROR;
+ break;
+ case IBES_INTEGER:
+ State = IBES_DIVIDE;
+ IC.pushOperator(IC_DIVIDE);
break;
}
}
@@ -843,8 +997,8 @@ public:
State = IBES_ERROR;
break;
case IBES_RBRAC:
- State = IBES_START;
- isPlus = true;
+ State = IBES_PLUS;
+ IC.pushOperator(IC_PLUS);
break;
}
}
@@ -853,15 +1007,9 @@ public:
default:
State = IBES_ERROR;
break;
- case IBES_DISP_EXPR:
- State = IBES_RBRAC;
- break;
+ case IBES_RPAREN:
case IBES_INTEGER:
State = IBES_RBRAC;
- if (isPlus)
- Disp += TmpInteger;
- else
- Disp -= TmpInteger;
break;
case IBES_REGISTER:
State = IBES_RBRAC;
@@ -875,8 +1023,38 @@ public:
Scale = 1;
}
break;
- case IBES_INDEX_REGISTER:
- State = IBES_RBRAC;
+ }
+ }
+ void onLParen() {
+ switch (State) {
+ default:
+ State = IBES_ERROR;
+ break;
+ case IBES_PLUS:
+ case IBES_MINUS:
+ case IBES_MULTIPLY:
+ case IBES_DIVIDE:
+ case IBES_INTEGER_STAR:
+ case IBES_LPAREN:
+ State = IBES_LPAREN;
+ IC.pushOperator(IC_LPAREN);
+ break;
+ }
+ }
+ void onRParen() {
+ switch (State) {
+ default:
+ State = IBES_ERROR;
+ break;
+ case IBES_REGISTER:
+ case IBES_INTEGER:
+ case IBES_PLUS:
+ case IBES_MINUS:
+ case IBES_MULTIPLY:
+ case IBES_DIVIDE:
+ case IBES_RPAREN:
+ State = IBES_RPAREN;
+ IC.pushOperator(IC_RPAREN);
break;
}
}
@@ -1005,16 +1183,20 @@ X86Operand *X86AsmParser::ParseIntelBracExpression(unsigned SegReg,
}
return ErrorOperand(Tok.getLoc(), "Unexpected identifier!");
}
- case AsmToken::Integer: {
- int64_t Val = Tok.getIntVal();
- SM.onInteger(Val);
+ case AsmToken::Integer:
+ if (isParsingInlineAsm())
+ InstInfo->AsmRewrites->push_back(AsmRewrite(AOK_ImmPrefix,
+ Tok.getLoc()));
+ SM.onInteger(Tok.getIntVal());
break;
- }
case AsmToken::Plus: SM.onPlus(); break;
case AsmToken::Minus: SM.onMinus(); break;
case AsmToken::Star: SM.onStar(); break;
+ case AsmToken::Slash: SM.onDivide(); break;
case AsmToken::LBrac: SM.onLBrac(); break;
case AsmToken::RBrac: SM.onRBrac(); break;
+ case AsmToken::LParen: SM.onLParen(); break;
+ case AsmToken::RParen: SM.onRParen(); break;
}
if (!Done && UpdateLocLex) {
End = Tok.getLoc();
diff --git a/test/MC/X86/intel-syntax.s b/test/MC/X86/intel-syntax.s
index 8bfa58a4be..226757b305 100644
--- a/test/MC/X86/intel-syntax.s
+++ b/test/MC/X86/intel-syntax.s
@@ -247,4 +247,41 @@ _main:
mov [16][eax][ebx*4], ecx
// CHECK: movl %ecx, -16(%eax,%ebx,4)
mov [eax][ebx*4 - 16], ecx
- ret
+
+// CHECK: prefetchnta 12800(%esi)
+ prefetchnta [esi + (200*64)]
+// CHECK: prefetchnta 32(%esi)
+ prefetchnta [esi + (64/2)]
+// CHECK: prefetchnta 128(%esi)
+ prefetchnta [esi + (64/2*4)]
+// CHECK: prefetchnta 8(%esi)
+ prefetchnta [esi + (64/(2*4))]
+// CHECK: prefetchnta 48(%esi)
+ prefetchnta [esi + (64/(2*4)+40)]
+
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [eax][ebx*4 - 2*8], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [eax][4*ebx - 2*8], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [eax + 4*ebx - 2*8], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [12 + eax + (4*ebx) - 2*14], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [eax][ebx*4 - 2*2*2*2], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [eax][ebx*4 - (2*8)], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [eax][ebx*4 - 2 * 8 + 4 - 4], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [eax + ebx*4 - 2 * 8 + 4 - 4], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [eax + ebx*4 - 2 * ((8 + 4) - 4)], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [-2 * ((8 + 4) - 4) + eax + ebx*4], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [((-2) * ((8 + 4) - 4)) + eax + ebx*4], ecx
+// CHECK: movl %ecx, -16(%eax,%ebx,4)
+ mov [eax + ((-2) * ((8 + 4) - 4)) + ebx*4], ecx
+
+ ret