From e112453fc39b97147ea3f23bf0b1973cd9f739b1 Mon Sep 17 00:00:00 2001 From: Chad Rosier Date: Fri, 5 Apr 2013 16:28:55 +0000 Subject: [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 --- lib/Target/X86/AsmParser/X86AsmParser.cpp | 310 ++++++++++++++++++++++++------ test/MC/X86/intel-syntax.s | 39 +++- 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 InfixOperatorStack; + SmallVector 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 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 -- cgit v1.2.3