source: CLRX/CLRadeonExtender/trunk/amdasm/AsmExpression.cpp @ 3772

Last change on this file since 3772 was 3772, checked in by matszpk, 3 years ago

CLRadeonExtender: Asm: First working AsmROCm with section differences.

File size: 74.1 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2018 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#include <string>
22#include <vector>
23#include <stack>
24#include <algorithm>
25#include <unordered_set>
26#include <unordered_map>
27#include <CLRX/utils/Utilities.h>
28#include <CLRX/amdasm/Assembler.h>
29#include "AsmInternals.h"
30
31using namespace CLRX;
32
33/*
34 * expressions
35 */
36
37// bitmask: if bit is enabled then operator can give message (error or warning)
38static const uint64_t operatorWithMessage = 
39        (1ULL<<int(AsmExprOp::DIVISION)) | (1ULL<<int(AsmExprOp::SIGNED_DIVISION)) |
40        (1ULL<<int(AsmExprOp::MODULO)) | (1ULL<<int(AsmExprOp::SIGNED_MODULO)) |
41        (1ULL<<int(AsmExprOp::SHIFT_LEFT)) | (1ULL<<int(AsmExprOp::SHIFT_RIGHT)) |
42        (1ULL<<int(AsmExprOp::SIGNED_SHIFT_RIGHT));
43
44AsmExpression::AsmExpression() : symOccursNum(0), relativeSymOccurs(false),
45            baseExpr(false)
46{ }
47
48// set symbol occurrences, operators and arguments, line positions for messages
49void AsmExpression::setParams(size_t _symOccursNum,
50          bool _relativeSymOccurs, size_t _opsNum, const AsmExprOp* _ops, size_t _opPosNum,
51          const LineCol* _opPos, size_t _argsNum, const AsmExprArg* _args, bool _baseExpr)
52{
53    symOccursNum = _symOccursNum;
54    relativeSymOccurs = _relativeSymOccurs;
55    baseExpr = _baseExpr;
56    args.reset(new AsmExprArg[_argsNum]);
57    ops.assign(_ops, _ops+_opsNum);
58    messagePositions.reset(new LineCol[_opPosNum]);
59    std::copy(_args, _args+_argsNum, args.get());
60    std::copy(_opPos, _opPos+_opPosNum, messagePositions.get());
61}
62
63AsmExpression::AsmExpression(const AsmSourcePos& _pos, size_t _symOccursNum,
64          bool _relSymOccurs, size_t _opsNum, const AsmExprOp* _ops, size_t _opPosNum,
65          const LineCol* _opPos, size_t _argsNum, const AsmExprArg* _args,
66          bool _baseExpr)
67        : sourcePos(_pos), symOccursNum(_symOccursNum), relativeSymOccurs(_relSymOccurs),
68          baseExpr(_baseExpr), ops(_ops, _ops+_opsNum)
69{
70    args.reset(new AsmExprArg[_argsNum]);
71    messagePositions.reset(new LineCol[_opPosNum]);
72    std::copy(_args, _args+_argsNum, args.get());
73    std::copy(_opPos, _opPos+_opPosNum, messagePositions.get());
74}
75
76AsmExpression::AsmExpression(const AsmSourcePos& _pos, size_t _symOccursNum,
77            bool _relSymOccurs, size_t _opsNum, size_t _opPosNum, size_t _argsNum,
78            bool _baseExpr)
79        : sourcePos(_pos), symOccursNum(_symOccursNum), relativeSymOccurs(_relSymOccurs),
80          baseExpr(_baseExpr), ops(_opsNum)
81{
82    args.reset(new AsmExprArg[_argsNum]);
83    messagePositions.reset(new LineCol[_opPosNum]);
84}
85
86AsmExpression::~AsmExpression()
87{
88    if (!baseExpr)
89    {
90        // delete all occurrences in expression at that place
91        for (size_t i = 0, j = 0; i < ops.size(); i++)
92            if (ops[i] == AsmExprOp::ARG_SYMBOL)
93            {
94                args[j].symbol->second.removeOccurrenceInExpr(this, j, i);
95                j++;
96            }
97            else if (ops[i]==AsmExprOp::ARG_VALUE)
98                j++;
99    }
100}
101
102// helper for handling errors
103
104#define ASMX_FAILED_BY_ERROR(PLACE, STRING) \
105    { \
106        assembler.printError(PLACE, STRING); \
107        failed = true; \
108    }
109
110#define ASMX_NOTGOOD_BY_ERROR(PLACE, STRING) \
111    { \
112        assembler.printError(PLACE, STRING); \
113        good = false; \
114    }
115
116// expression with relative symbols
117struct RelMultiply
118{
119    // multiplication of section
120    uint64_t multiply;
121    cxuint sectionId;
122};
123
124static inline bool compareRelMSectionLess(const RelMultiply& r1, const RelMultiply& r2)
125{ return r1.sectionId < r2.sectionId; }
126
127static void reduceRelMultiplies(std::vector<RelMultiply>& relmuls)
128{
129    size_t i = 0, j = 0;
130    uint64_t multiply = 0;
131    cxuint prevSect = ASMSECT_ABS;
132    for (i = 0; i < relmuls.size(); i++)
133    {
134        if (relmuls[i].sectionId != prevSect)
135        {
136            if (i != 0)
137                relmuls[j++] = { multiply, prevSect };
138            multiply = relmuls[i].multiply;
139            prevSect = relmuls[i].sectionId;
140        }
141        else
142            multiply += relmuls[i].multiply;
143    }
144    if (i != 0)
145        relmuls[j++] = { multiply, prevSect };
146    relmuls.resize(j);
147}
148
149static bool checkRelativesEquality(Assembler& assembler,
150            std::vector<RelMultiply>& relatives,
151            const Array<RelMultiply>& relatives2, bool checkRelSpaces,
152            uint64_t& fixAddr1, uint64_t& fixAddr2)
153{
154    fixAddr1 = 0;
155    fixAddr2 = 0;
156    // if no check relspaces or if no real rel spaces in relatives
157    bool equal = true;
158    size_t requals = 0;
159    if (relatives2.size() != relatives.size())
160        equal = false;
161    else
162    {
163        // check whether relatives as same in two operands
164        for (const RelMultiply& r: relatives2)
165            for (RelMultiply& r2: relatives)
166                if (r.multiply == r2.multiply &&
167                        r.sectionId == r2.sectionId)
168                {
169                    r2.sectionId = ASMSECT_ABS; // ignore in next iter
170                    requals++;
171                    break;
172                }
173        if (requals != relatives.size())
174            equal = false;
175    }
176   
177    if (equal) // if equal in previous method
178        return true;
179   
180    if (!checkRelSpaces) // otherwise is not equal
181        return false;
182   
183    std::vector<RelMultiply> relSpaces1(relatives.size());
184    std::vector<RelMultiply> relSpaces2(relatives2.size());
185    const std::vector<AsmSection>& sections = assembler.getSections();
186    const std::vector<Array<cxuint> >& relSpacesSects = assembler.getRelSpacesSections();
187   
188    // convert sections to relspaces
189    for (size_t i = 0; i < relSpaces1.size(); i++)
190        if (sections[relatives[i].sectionId].relSpace != UINT_MAX)
191        {
192            cxuint osectId = relatives[i].sectionId;
193            relSpaces1[i] = { relatives[i].multiply, 
194                    sections[osectId].relSpace };
195            cxuint rsectId = relSpacesSects[sections[osectId].relSpace][0];
196            fixAddr1 = relatives[i].multiply*(sections[osectId].relAddress -
197                    sections[rsectId].relAddress);
198        }
199        else // treat as separate relSpace
200            relSpaces1[i] = { relatives[i].multiply,
201                    0x80000000 | relatives[i].sectionId };
202   
203    for (size_t i = 0; i < relSpaces2.size(); i++)
204        if (sections[relatives2[i].sectionId].relSpace != UINT_MAX)
205        {
206            cxuint osectId = relatives2[i].sectionId;
207            relSpaces1[i] = { relatives2[i].multiply,
208                    sections[osectId].relSpace };
209            cxuint rsectId = relSpacesSects[sections[osectId].relSpace][0];
210            fixAddr1 = relatives2[i].multiply*(sections[osectId].relAddress -
211                    sections[rsectId].relAddress);
212        }
213        else // treat as separate relSpace
214            relSpaces2[i] = { relatives2[i].multiply,
215                    0x80000000 | relatives2[i].sectionId };
216   
217    // sort
218    std::sort(relSpaces1.begin(), relSpaces1.end(), compareRelMSectionLess);
219    std::sort(relSpaces2.begin(), relSpaces2.end(), compareRelMSectionLess);
220    // reduce relspaces by sum multiplies
221    reduceRelMultiplies(relSpaces1);
222    reduceRelMultiplies(relSpaces2);
223   
224    /// compare relspaces
225    if (relSpaces1.size() != relSpaces2.size())
226        return false;
227    for (size_t i = 0; i < relSpaces1.size(); i++)
228        if (relSpaces1[i].multiply != relSpaces2[i].multiply ||
229            relSpaces1[i].sectionId != relSpaces2[i].sectionId)
230            return false;
231    return true;
232}
233
234AsmTryStatus AsmExpression::tryEvaluate(Assembler& assembler, size_t opStart, size_t opEnd,
235                 uint64_t& outValue, cxuint& outSectionId, bool withSectionDiffs) const
236{
237    if (symOccursNum != 0)
238        throw AsmException("Expression can't be evaluated if "
239                    "symbols still are unresolved!");
240   
241    bool failed = false;
242    bool tryLater = false;
243    uint64_t value = 0; // by default is zero
244    cxuint sectionId = 0;
245    if (!relativeSymOccurs)
246    {
247        // all value is absolute
248        std::stack<uint64_t> stack;
249       
250        size_t argPos = 0;
251        size_t opPos = 0;
252        size_t messagePosIndex = 0;
253       
254        // move messagePosIndex and argument position to opStart position
255        for (opPos = 0; opPos < opStart; opPos++)
256        {
257            if (ops[opPos]==AsmExprOp::ARG_VALUE)
258                argPos++;
259            if ((operatorWithMessage & (1ULL<<cxuint(ops[opPos])))!=0)
260                messagePosIndex++;
261        }
262       
263        while (opPos < opEnd)
264        {
265            const AsmExprOp op = ops[opPos++];
266            if (op == AsmExprOp::ARG_VALUE)
267            {
268                // push argument to stack
269                stack.push(args[argPos++].value);
270                continue;
271            }
272            value = stack.top();
273            stack.pop();
274            if (isUnaryOp(op))
275            {
276                // unary operator (-,~,!)
277                switch (op)
278                {
279                    case AsmExprOp::NEGATE:
280                        value = -value;
281                        break;
282                    case AsmExprOp::BIT_NOT:
283                        value = ~value;
284                        break;
285                    case AsmExprOp::LOGICAL_NOT:
286                        value = !value;
287                        break;
288                    default:
289                        break;
290                }
291            }
292            else if (isBinaryOp(op))
293            {
294                // get first argument (second in stack)
295                uint64_t value2 = stack.top();
296                stack.pop();
297                switch (op)
298                {
299                    case AsmExprOp::ADDITION:
300                        value = value2 + value;
301                        break;
302                    case AsmExprOp::SUBTRACT:
303                        value = value2 - value;
304                        break;
305                    case AsmExprOp::MULTIPLY:
306                        value = value2 * value;
307                        break;
308                    case AsmExprOp::DIVISION:
309                        if (value != 0)
310                            value = value2 / value;
311                        else // error
312                        {
313                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
314                                   "Division by zero")
315                            value = 0;
316                        }
317                        messagePosIndex++;
318                        break;
319                    case AsmExprOp::SIGNED_DIVISION:
320                        if (value != 0)
321                            value = int64_t(value2) / int64_t(value);
322                        else // error
323                        {
324                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
325                                   "Division by zero")
326                            value = 0;
327                        }
328                        messagePosIndex++;
329                        break;
330                    case AsmExprOp::MODULO:
331                        if (value != 0)
332                            value = value2 % value;
333                        else // error
334                        {
335                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
336                                   "Division by zero")
337                            value = 0;
338                        }
339                        messagePosIndex++;
340                        break;
341                    case AsmExprOp::SIGNED_MODULO:
342                        if (value != 0)
343                            value = int64_t(value2) % int64_t(value);
344                        else // error
345                        {
346                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
347                                   "Division by zero")
348                            value = 0;
349                        }
350                        messagePosIndex++;
351                        break;
352                    case AsmExprOp::BIT_AND:
353                        value = value2 & value;
354                        break;
355                    case AsmExprOp::BIT_OR:
356                        value = value2 | value;
357                        break;
358                    case AsmExprOp::BIT_XOR:
359                        value = value2 ^ value;
360                        break;
361                    case AsmExprOp::BIT_ORNOT:
362                        value = value2 | ~value;
363                        break;
364                    case AsmExprOp::SHIFT_LEFT:
365                        if (value < 64)
366                            value = value2 << value;
367                        else
368                        {
369                            assembler.printWarning(getSourcePos(messagePosIndex),
370                                   "Shift count out of range (between 0 and 63)");
371                            value = 0;
372                        }
373                        messagePosIndex++;
374                        break;
375                    case AsmExprOp::SHIFT_RIGHT:
376                        if (value < 64)
377                            value = value2 >> value;
378                        else
379                        {
380                            assembler.printWarning(getSourcePos(messagePosIndex),
381                                   "Shift count out of range (between 0 and 63)");
382                            value = 0;
383                        }
384                        messagePosIndex++;
385                        break;
386                    case AsmExprOp::SIGNED_SHIFT_RIGHT:
387                        if (value < 64)
388                            value = int64_t(value2) >> value;
389                        else
390                        {
391                            assembler.printWarning(getSourcePos(messagePosIndex),
392                                   "Shift count out of range (between 0 and 63)");
393                            value = (value2>=(1ULL<<63)) ? UINT64_MAX : 0;
394                        }
395                        messagePosIndex++;
396                        break;
397                    case AsmExprOp::LOGICAL_AND:
398                        value = value2 && value;
399                        break;
400                    case AsmExprOp::LOGICAL_OR:
401                        value = value2 || value;
402                        break;
403                    case AsmExprOp::EQUAL:
404                        value = (value2 == value) ? UINT64_MAX : 0;
405                        break;
406                    case AsmExprOp::NOT_EQUAL:
407                        value = (value2 != value) ? UINT64_MAX : 0;
408                        break;
409                    case AsmExprOp::LESS:
410                        value = (int64_t(value2) < int64_t(value))? UINT64_MAX: 0;
411                        break;
412                    case AsmExprOp::LESS_EQ:
413                        value = (int64_t(value2) <= int64_t(value)) ? UINT64_MAX : 0;
414                        break;
415                    case AsmExprOp::GREATER:
416                        value = (int64_t(value2) > int64_t(value)) ? UINT64_MAX : 0;
417                        break;
418                    case AsmExprOp::GREATER_EQ:
419                        value = (int64_t(value2) >= int64_t(value)) ? UINT64_MAX : 0;
420                        break;
421                    case AsmExprOp::BELOW:
422                        value = (value2 < value)? UINT64_MAX: 0;
423                        break;
424                    case AsmExprOp::BELOW_EQ:
425                        value = (value2 <= value) ? UINT64_MAX : 0;
426                        break;
427                    case AsmExprOp::ABOVE:
428                        value = (value2 > value) ? UINT64_MAX : 0;
429                        break;
430                    case AsmExprOp::ABOVE_EQ:
431                        value = (value2 >= value) ? UINT64_MAX : 0;
432                        break;
433                    default:
434                        break;
435                }
436            }
437            else if (op == AsmExprOp::CHOICE)
438            {
439                // get second and first (second and third in stack)
440                const uint64_t value2 = stack.top();
441                stack.pop();
442                const uint64_t value3 = stack.top();
443                stack.pop();
444                value = value3 ? value2 : value;
445            }
446            stack.push(value);
447        }
448       
449        if (!stack.empty())
450            value = stack.top();
451        sectionId = ASMSECT_ABS;
452    }
453    else
454    {
455        const bool sectDiffsPrepared = assembler.sectionDiffsPrepared;
456       
457        // structure that contains relatives info: offset value and mult. of sections
458        struct ValueAndMultiplies
459        {
460            uint64_t value;
461            Array<RelMultiply> relatives;
462           
463            ValueAndMultiplies(uint64_t _value = 0) : value(_value)
464            { }
465            ValueAndMultiplies(uint64_t _value, cxuint _sectionId) : value(_value),
466                relatives({{1,_sectionId}})
467            { }
468        };
469       
470        std::stack<ValueAndMultiplies> stack;
471        size_t argPos = 0;
472        size_t opPos = 0;
473        size_t messagePosIndex = 0;
474        std::vector<RelMultiply> relatives;
475       
476        // move messagePosIndex and argument position to opStart position
477        for (opPos = 0; opPos < opStart; opPos++)
478        {
479            if (ops[opPos]==AsmExprOp::ARG_VALUE)
480                argPos++;
481            if ((operatorWithMessage & (1ULL<<cxuint(ops[opPos])))!=0)
482                messagePosIndex++;
483        }
484       
485        const std::vector<Array<cxuint> >& relSpacesSects = assembler.relSpacesSections;
486        const std::vector<AsmSection>& sections = assembler.sections;
487       
488        while (opPos < opEnd)
489        {
490            const AsmExprOp op = ops[opPos++];
491            if (op == AsmExprOp::ARG_VALUE)
492            {
493                if (args[argPos].relValue.sectionId != ASMSECT_ABS)
494                {
495                    uint64_t ovalue = args[argPos].relValue.value;
496                    cxuint osectId = args[argPos].relValue.sectionId;
497                    if (sectDiffsPrepared && sections[osectId].relSpace!=UINT_MAX)
498                    {
499                        // resolve section in relspace
500                        cxuint rsectId = relSpacesSects[sections[osectId].relSpace][0];
501                        ovalue += sections[osectId].relAddress -
502                                sections[rsectId].relAddress;
503                        osectId = rsectId;
504                    }
505                    stack.push(ValueAndMultiplies(ovalue, osectId));
506                }
507                else
508                    stack.push(args[argPos].value);
509                argPos++;
510                continue;
511            }
512            value = stack.top().value;
513            relatives.assign(stack.top().relatives.begin(), stack.top().relatives.end());
514            stack.pop();
515           
516            // handle unary operators
517            if (isUnaryOp(op))
518            {
519                switch (op)
520                {
521                    case AsmExprOp::NEGATE:
522                        for (RelMultiply& r: relatives)
523                            r.multiply = -r.multiply;
524                        value = -value;
525                        break;
526                    case AsmExprOp::BIT_NOT:
527                        for (RelMultiply& r: relatives)
528                            r.multiply = -r.multiply;
529                        value = ~value;
530                        break;
531                    case AsmExprOp::LOGICAL_NOT:
532                        if (!relatives.empty())
533                            ASMX_FAILED_BY_ERROR(sourcePos,
534                                 "Logical negation is not allowed to relative values")
535                        value = !value;
536                        break;
537                    default:
538                        break;
539                }
540            }
541            else if (isBinaryOp(op))
542            {
543                uint64_t value2 = stack.top().value;
544                const Array<RelMultiply> relatives2 = stack.top().relatives;
545                stack.pop();
546                switch (op)
547                {
548                    case AsmExprOp::ADDITION:
549                    case AsmExprOp::SUBTRACT:
550                    {
551                        if (op == AsmExprOp::SUBTRACT)
552                        {
553                            for (RelMultiply& r: relatives)
554                                r.multiply = -r.multiply; // negate before subtraction
555                            value = -value;
556                        }
557                        for (const RelMultiply& r2: relatives2)
558                        {
559                            bool rfound = false;
560                            for (RelMultiply& r: relatives)
561                                if (r.sectionId == r2.sectionId)
562                                {
563                                    r.multiply += r2.multiply;
564                                    rfound = true;
565                                }
566                           if (!rfound)
567                               relatives.push_back(r2);
568                        }
569                        // remove zeroes from relatives
570                        relatives.resize(std::remove_if(relatives.begin(), relatives.end(),
571                           [](const RelMultiply& r) { return r.multiply==0; }) -
572                           relatives.begin());
573                        value = value2 + value;
574                        break;
575                    }
576                    case AsmExprOp::MULTIPLY:
577                        // we do not multiply with relatives in two operands
578                        if (!relatives.empty() && !relatives2.empty())
579                            ASMX_FAILED_BY_ERROR(sourcePos,
580                                 "Multiplication is not allowed for two relative values")
581                        if (relatives2.empty())
582                        {
583                            // multiply relatives
584                            if (value2 != 0)
585                                for (RelMultiply& r: relatives)
586                                    r.multiply *= value2;
587                            else
588                                relatives.clear();
589                        }
590                        else
591                        {
592                            // multiply relatives2
593                            if (value != 0)
594                            {
595                                relatives.assign(relatives2.begin(), relatives2.end());
596                                for (RelMultiply& r: relatives)
597                                    r.multiply *= value;
598                            }
599                        }
600                        value = value2 * value;
601                        break;
602                    case AsmExprOp::DIVISION:
603                        if (!relatives.empty() || !relatives2.empty())
604                            ASMX_FAILED_BY_ERROR(sourcePos,
605                                 "Division is not allowed for any relative value")
606                        if (value != 0)
607                            value = value2 / value;
608                        else
609                        {
610                            // error
611                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
612                                   "Division by zero")
613                            value = 0;
614                        }
615                        messagePosIndex++;
616                        break;
617                    case AsmExprOp::SIGNED_DIVISION:
618                        if (!relatives.empty()|| !relatives2.empty())
619                            ASMX_FAILED_BY_ERROR(sourcePos,
620                                 "Signed division is not allowed for any relative value")
621                        if (value != 0)
622                            value = int64_t(value2) / int64_t(value);
623                        else
624                        {
625                            // error
626                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
627                                   "Division by zero")
628                            value = 0;
629                        }
630                        messagePosIndex++;
631                        break;
632                    case AsmExprOp::MODULO:
633                        if (!relatives.empty() || !relatives2.empty())
634                            ASMX_FAILED_BY_ERROR(sourcePos,
635                                 "Modulo is not allowed for any relative value")
636                        if (value != 0)
637                            value = value2 % value;
638                        else
639                        {
640                            // error
641                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
642                                   "Division by zero")
643                            value = 0;
644                        }
645                        messagePosIndex++;
646                        break;
647                    case AsmExprOp::SIGNED_MODULO:
648                        if (!relatives.empty() || !relatives2.empty())
649                            ASMX_FAILED_BY_ERROR(sourcePos,
650                                 "Signed Modulo is not allowed for any relative value")
651                        if (value != 0)
652                            value = int64_t(value2) % int64_t(value);
653                        else
654                        {
655                            // error
656                            ASMX_FAILED_BY_ERROR(getSourcePos(messagePosIndex),
657                                   "Division by zero")
658                            value = 0;
659                        }
660                        messagePosIndex++;
661                        break;
662                    case AsmExprOp::BIT_AND:
663                        if (!relatives.empty() || !relatives2.empty())
664                            ASMX_FAILED_BY_ERROR(sourcePos,
665                                 "Binary AND is not allowed for any relative value")
666                        value = value2 & value;
667                        break;
668                    case AsmExprOp::BIT_OR:
669                        if (!relatives.empty() || !relatives2.empty())
670                            ASMX_FAILED_BY_ERROR(sourcePos,
671                                 "Binary OR is not allowed for any relative value")
672                        value = value2 | value;
673                        break;
674                    case AsmExprOp::BIT_XOR:
675                        if (!relatives.empty() || !relatives2.empty())
676                            ASMX_FAILED_BY_ERROR(sourcePos,
677                                 "Binary XOR is not allowed for any relative value")
678                        value = value2 ^ value;
679                        break;
680                    case AsmExprOp::BIT_ORNOT:
681                        if (!relatives.empty() || !relatives2.empty())
682                            ASMX_FAILED_BY_ERROR(sourcePos,
683                                 "Binary ORNOT is not allowed for any relative value")
684                        value = value2 | ~value;
685                        break;
686                    case AsmExprOp::SHIFT_LEFT:
687                        if (!relatives.empty())
688                            ASMX_FAILED_BY_ERROR(sourcePos, "Shift left is not allowed "
689                                    "for any for relative second value")
690                        else if (value < 64)
691                        {
692                            relatives.assign(relatives2.begin(), relatives2.end());
693                            for (RelMultiply& r: relatives)
694                                r.multiply <<= value;
695                            value = value2 << value;
696                        }
697                        else
698                        {
699                            assembler.printWarning(getSourcePos(messagePosIndex),
700                                   "Shift count out of range (between 0 and 63)");
701                            value = 0;
702                        }
703                        messagePosIndex++;
704                        break;
705                    case AsmExprOp::SHIFT_RIGHT:
706                        if (!relatives.empty() || !relatives2.empty())
707                            ASMX_FAILED_BY_ERROR(sourcePos,
708                                 "Shift right is not allowed for any relative value")
709                        if (value < 64)
710                            value = value2 >> value;
711                        else
712                        {
713                            assembler.printWarning(getSourcePos(messagePosIndex),
714                                   "Shift count out of range (between 0 and 63)");
715                            value = 0;
716                        }
717                        messagePosIndex++;
718                        break;
719                    case AsmExprOp::SIGNED_SHIFT_RIGHT:
720                        if (!relatives.empty() || !relatives2.empty())
721                            ASMX_FAILED_BY_ERROR(sourcePos, "Signed shift right is not "
722                                    "allowed for any relative value")
723                        if (value < 64)
724                            value = int64_t(value2) >> value;
725                        else
726                        {
727                            assembler.printWarning(getSourcePos(messagePosIndex),
728                                   "Shift count out of range (between 0 and 63)");
729                            value = (value2>=(1ULL<<63)) ? UINT64_MAX : 0;
730                        }
731                        messagePosIndex++;
732                        break;
733                    case AsmExprOp::LOGICAL_AND:
734                        if (!relatives.empty() || !relatives2.empty())
735                            ASMX_FAILED_BY_ERROR(sourcePos,
736                                 "Logical AND is not allowed for any relative value")
737                        value = value2 && value;
738                        break;
739                    case AsmExprOp::LOGICAL_OR:
740                        if (!relatives.empty() || !relatives2.empty())
741                            ASMX_FAILED_BY_ERROR(sourcePos,
742                                 "Logical OR is not allowed for any relative value")
743                        value = value2 || value;
744                        break;
745                    case AsmExprOp::EQUAL:
746                    case AsmExprOp::NOT_EQUAL:
747                    case AsmExprOp::LESS:
748                    case AsmExprOp::LESS_EQ:
749                    case AsmExprOp::GREATER:
750                    case AsmExprOp::GREATER_EQ:
751                    case AsmExprOp::BELOW:
752                    case AsmExprOp::BELOW_EQ:
753                    case AsmExprOp::ABOVE:
754                    case AsmExprOp::ABOVE_EQ:
755                    {
756                        uint64_t fixAddr1 = 0, fixAddr2 = 0;
757                        if (!checkRelativesEquality(assembler, relatives, relatives2,
758                                    withSectionDiffs && !sectDiffsPrepared,
759                                    fixAddr1, fixAddr2))
760                            ASMX_FAILED_BY_ERROR(sourcePos, "For comparisons "
761                                        "two values must have this same relatives!")
762                       
763                        if (withSectionDiffs && !sectDiffsPrepared)
764                            tryLater = true; // must be evaluated later
765                        relatives.clear();
766                        value += fixAddr1;
767                        value2 += fixAddr2;
768                        switch(op)
769                        {
770                            case AsmExprOp::EQUAL:
771                                value = (value2 == value) ? UINT64_MAX : 0;
772                                break;
773                            case AsmExprOp::NOT_EQUAL:
774                                value = (value2 != value) ? UINT64_MAX : 0;
775                                break;
776                            case AsmExprOp::LESS:
777                                value = (int64_t(value2) < int64_t(value))? UINT64_MAX: 0;
778                                break;
779                            case AsmExprOp::LESS_EQ:
780                                value = (int64_t(value2) <= int64_t(value)) ?
781                                        UINT64_MAX : 0;
782                                break;
783                            case AsmExprOp::GREATER:
784                                value = (int64_t(value2) > int64_t(value)) ? UINT64_MAX : 0;
785                                break;
786                            case AsmExprOp::GREATER_EQ:
787                                value = (int64_t(value2) >= int64_t(value)) ?
788                                        UINT64_MAX : 0;
789                                break;
790                            case AsmExprOp::BELOW:
791                                value = (value2 < value)? UINT64_MAX: 0;
792                                break;
793                            case AsmExprOp::BELOW_EQ:
794                                value = (value2 <= value)? UINT64_MAX: 0;
795                                break;
796                            case AsmExprOp::ABOVE:
797                                value = (value2 > value)? UINT64_MAX: 0;
798                                break;
799                            case AsmExprOp::ABOVE_EQ:
800                                value = (value2 >= value)? UINT64_MAX: 0;
801                                break;
802                            default:
803                                break;
804                        }
805                        break;
806                    }
807                    default:
808                        break;
809                }
810            }
811            else if (op == AsmExprOp::CHOICE)
812            {
813                const uint64_t value2 = stack.top().value;
814                const Array<RelMultiply> relatives2 = stack.top().relatives;
815                stack.pop();
816                const uint64_t value3 = stack.top().value;
817                const Array<RelMultiply> relatives3 = stack.top().relatives;
818                stack.pop();
819                if (!relatives3.empty())
820                    ASMX_FAILED_BY_ERROR(sourcePos,
821                         "Choice is not allowed for first relative value")
822                if (value3)
823                    relatives.assign(relatives2.begin(), relatives2.end());
824                value = value3 ? value2 : value;
825            }
826           
827            ValueAndMultiplies relOut(value);
828            relOut.relatives.assign(relatives.begin(), relatives.end());
829            stack.push(relOut);
830        }
831       
832        if (!stack.empty())
833        {
834            value = stack.top().value;
835            relatives.assign(stack.top().relatives.begin(), stack.top().relatives.end());
836        }
837       
838        if (relatives.empty())
839            sectionId = ASMSECT_ABS;
840        else if (relatives.size() == 1 && relatives.front().multiply == 1)
841            sectionId = relatives.front().sectionId;
842        else
843        {
844            bool moreThanOneRelSpace = false;
845            cxuint relSpace = UINT_MAX;
846            if (withSectionDiffs && !sectDiffsPrepared)
847                // resolve whether is one relspace or not
848                for (const RelMultiply r: relatives)
849                {
850                    if (sections[r.sectionId].relSpace != UINT_MAX)
851                    {
852                        if (relSpace != UINT_MAX &&
853                            relSpace != sections[r.sectionId].relSpace)
854                        {
855                            moreThanOneRelSpace = true;
856                            break;
857                        }
858                        relSpace = sections[r.sectionId].relSpace;
859                    }
860                    else // treat section without relspace as separate relspace
861                    {
862                        moreThanOneRelSpace = true;
863                        break;
864                    }
865                }
866            else
867                moreThanOneRelSpace = true;
868           
869            if (moreThanOneRelSpace)
870                ASMX_FAILED_BY_ERROR(sourcePos,
871                        "Only one relative=1 (section) can be result of expression")
872            else // not sure, should be evaluated after section diffs resolving
873                tryLater = true;
874        }
875       
876        if (sectDiffsPrepared && sectionId != ASMSECT_ABS &&
877            sections[sectionId].relSpace != UINT_MAX)
878        {   // find proper section
879            const Array<cxuint>& rlSections  = relSpacesSects[
880                                sections[sectionId].relSpace];
881            uint64_t valAddr = sections[sectionId].relAddress + value;
882            auto it = std::lower_bound(rlSections.begin(), rlSections.end(), ASMSECT_ABS,
883                [&sections,valAddr](cxuint a, cxuint b)
884                {
885                    uint64_t relAddr1 = a!=ASMSECT_ABS ? sections[a].relAddress : valAddr;
886                    uint64_t relAddr2 = b!=ASMSECT_ABS ? sections[b].relAddress : valAddr;
887                    return relAddr1 < relAddr2;
888                });
889            // if section address higher than current address
890            if ((it == rlSections.end() || sections[*it].relAddress != valAddr) &&
891                    it != rlSections.begin())
892                --it;
893           
894            cxuint newSectionId = (it != rlSections.end()) ? *it : rlSections.back();
895            value += sections[sectionId].relAddress - sections[newSectionId].relAddress;
896            sectionId = newSectionId;
897        }
898    }
899    if (tryLater)
900        return AsmTryStatus::TRY_LATER;
901    if (!failed)
902    {
903        // write results only if no errors
904        outSectionId = sectionId;
905        outValue = value;
906    }
907    return failed ? AsmTryStatus::FAILED : AsmTryStatus::SUCCESS;
908}
909
910static const cxbyte asmOpPrioritiesTbl[] =
911{
912    /* higher value, higher priority */
913    7, // ARG_VALUE
914    7, // ARG_SYMBOL
915    6, // NEGATE
916    6, // BIT_NOT
917    6, // LOGICAL_NOT
918    6, // PLUS
919    3, // ADDITION
920    3, // SUBTRACT
921    5, // MULTIPLY
922    5, // DIVISION
923    5, // SIGNED_DIVISION
924    5, // MODULO
925    5, // SIGNED_MODULO
926    4, // BIT_AND
927    4, // BIT_OR
928    4, // BIT_XOR
929    4, // BIT_ORNOT
930    5, // SHIFT_LEFT
931    5, // SHIFT_RIGHT
932    5, // SIGNED_SHIFT_RIGHT
933    1, // LOGICAL_AND
934    1, // LOGICAL_OR
935    2, // EQUAL
936    2, // NOT_EQUAL
937    2, // LESS
938    2, // LESS_EQ
939    2, // GREATER
940    2, // GREATER_EQ
941    2, // BELOW
942    2, // BELOW_EQ
943    2, // ABOVE
944    2, // ABOVE_EQ
945    0, // CHOICE
946    0 // CHOICE_END
947};
948
949// method used also by AsmExprParse test co create expression from string
950AsmExpression* AsmExpression::parse(Assembler& assembler, size_t& linePos,
951                bool makeBase, bool dontResolveSymbolsLater)
952{
953    const char* outend = assembler.line+linePos;
954    AsmExpression* expr = parse(assembler, outend, makeBase, dontResolveSymbolsLater);
955    linePos = outend-(assembler.line+linePos);
956    return expr;
957}   
958
959struct CLRX_INTERNAL SymbolSnapshotHash: std::hash<CString>
960{
961    size_t operator()(const AsmSymbolEntry* e1) const
962    { return static_cast<const std::hash<CString>&>(*this)(e1->first); }
963};
964
965struct CLRX_INTERNAL SymbolSnapshotEqual
966{
967    bool operator()(const AsmSymbolEntry* e1, const AsmSymbolEntry* e2) const
968    { return e1->first == e2->first; }
969};
970
971/// internal class of temporary symbol (snapshot of symbol) map
972class CLRX_INTERNAL CLRX::AsmExpression::TempSymbolSnapshotMap: 
973        public std::unordered_set<AsmSymbolEntry*, SymbolSnapshotHash, SymbolSnapshotEqual>
974{ };
975
976AsmExpression* AsmExpression::createForSnapshot(const AsmSourcePos* exprSourcePos) const
977{
978    std::unique_ptr<AsmExpression> expr(new AsmExpression);
979    size_t argsNum = 0;
980    size_t msgPosNum = 0;
981    for (AsmExprOp op: ops)
982        if (AsmExpression::isArg(op))
983            argsNum++;
984        else if (operatorWithMessage & (1ULL<<int(op)))
985            msgPosNum++;
986    expr->sourcePos = sourcePos;
987    expr->sourcePos.exprSourcePos = exprSourcePos;
988    expr->ops = ops;
989    expr->args.reset(new AsmExprArg[argsNum]);
990    std::copy(args.get(), args.get()+argsNum, expr->args.get());
991    expr->messagePositions.reset(new LineCol[msgPosNum]);
992    std::copy(messagePositions.get(), messagePositions.get()+msgPosNum,
993              expr->messagePositions.get());
994    return expr.release();
995}
996
997/* create symbol entry for temporary snapshot expression. this is copy of
998 * original symbol entry that can holds snapshot expression instead of normal expression */
999static inline AsmSymbolEntry* createSymbolEntryForSnapshot(const AsmSymbolEntry& symEntry,
1000            const AsmSourcePos* exprSourcePos)
1001{
1002    std::unique_ptr<AsmExpression> expr(
1003            symEntry.second.expression->createForSnapshot(exprSourcePos));
1004   
1005    std::unique_ptr<AsmSymbolEntry> newSymEntry(new AsmSymbolEntry{
1006            symEntry.first, AsmSymbol(expr.get(), false, false)});
1007   
1008    expr->setTarget(AsmExprTarget::symbolTarget(newSymEntry.get()));
1009    expr.release();
1010    newSymEntry->second.base = true;
1011    return newSymEntry.release();
1012}
1013
1014// main routine to create symbol snapshot with snapshot expressions
1015bool AsmExpression::makeSymbolSnapshot(Assembler& assembler,
1016           TempSymbolSnapshotMap* snapshotMap, const AsmSymbolEntry& symEntry,
1017           AsmSymbolEntry*& outSymEntry, const AsmSourcePos* topParentSourcePos)
1018{
1019    struct StackEntry
1020    {
1021        AsmSymbolEntry* entry;
1022        size_t opIndex;
1023        size_t argIndex;
1024       
1025        explicit StackEntry(AsmSymbolEntry* _entry)
1026            : entry(_entry), opIndex(0), argIndex(0)
1027        { }
1028       
1029        AsmSymbolEntry* releaseEntry()
1030        {
1031            AsmSymbolEntry* out = entry;
1032            entry = nullptr;
1033            return out;
1034        }
1035    };
1036    std::stack<StackEntry> stack;
1037   
1038    outSymEntry = nullptr;
1039    {
1040        std::unique_ptr<AsmSymbolEntry> newSymEntry(
1041                    createSymbolEntryForSnapshot(symEntry, topParentSourcePos));
1042        auto res = snapshotMap->insert(newSymEntry.get());
1043        if (!res.second)
1044        {
1045            // do nothing (symbol snapshot already made)
1046            outSymEntry = *res.first;
1047            outSymEntry->second.refCount++;
1048            return true;
1049        }
1050        stack.push(StackEntry(newSymEntry.release()));
1051    }
1052   
1053    bool good = true;
1054   
1055    while (!stack.empty())
1056    {
1057        StackEntry& se = stack.top();
1058        size_t opIndex = se.opIndex;
1059        size_t argIndex = se.argIndex;
1060        AsmExpression* expr = se.entry->second.expression;
1061        const size_t opsSize = expr->ops.size();
1062       
1063        AsmExprArg* args = expr->args.get();
1064        AsmExprOp* ops = expr->ops.data();
1065        if (opIndex < opsSize)
1066        {
1067            for (; opIndex < opsSize; opIndex++)
1068                if (ops[opIndex] == AsmExprOp::ARG_SYMBOL)
1069                {
1070                    // check this symbol
1071                    AsmSymbolEntry* nextSymEntry = args[argIndex].symbol;
1072                    if (nextSymEntry->second.base)
1073                    {
1074                        // new base expression (set by using .'eqv')
1075                        std::unique_ptr<AsmSymbolEntry> newSymEntry(
1076                                    createSymbolEntryForSnapshot(*nextSymEntry,
1077                                     &(expr->sourcePos)));
1078                        auto res = snapshotMap->insert(newSymEntry.get());
1079                        if (!res.second)
1080                        {
1081                            // replace this symEntry by symbol from tempSymbolMap
1082                            nextSymEntry = *res.first;
1083                            args[argIndex].symbol = nextSymEntry;
1084                            nextSymEntry->second.refCount++;
1085                        }
1086                        else
1087                        {
1088                            // new symEntry to stack
1089                            stack.push(StackEntry(newSymEntry.release()));
1090                            se.argIndex = argIndex;
1091                            se.opIndex = opIndex;
1092                            break;
1093                        }
1094                    }
1095                   
1096                    if (nextSymEntry->second.hasValue)
1097                    {
1098                        // put value to argument
1099                        if (nextSymEntry->second.regRange)
1100                            ASMX_NOTGOOD_BY_ERROR(expr->getSourcePos(),
1101                                                 "Expression have register symbol")
1102                        ops[opIndex] = AsmExprOp::ARG_VALUE;
1103                        args[argIndex].relValue.value = nextSymEntry->second.value;
1104                        if (!assembler.isAbsoluteSymbol(nextSymEntry->second))
1105                        {
1106                            expr->relativeSymOccurs = true;
1107                            args[argIndex].relValue.sectionId = 
1108                                nextSymEntry->second.sectionId;
1109                        }
1110                        else
1111                            args[argIndex].relValue.sectionId = ASMSECT_ABS;
1112                    }
1113                    else // if not defined
1114                    {
1115                        args[argIndex].symbol->second.addOccurrenceInExpr(
1116                                        expr, argIndex, opIndex);
1117                        expr->symOccursNum++;
1118                    }
1119                   
1120                    argIndex++;
1121                }
1122                else if (ops[opIndex]==AsmExprOp::ARG_VALUE)
1123                    argIndex++;
1124        }
1125        if (opIndex == opsSize)
1126        {
1127            // check if expression is evaluatable
1128            AsmSymbolEntry* thisSymEntry = se.releaseEntry();
1129            if (expr->symOccursNum == 0) // no symbols, we try to evaluate
1130            {
1131                // evaluate and remove obsolete expression
1132                if (!expr->evaluate(assembler, thisSymEntry->second.value,
1133                            thisSymEntry->second.sectionId))
1134                    good = false;
1135                thisSymEntry->second.hasValue = true;
1136                delete thisSymEntry->second.expression;
1137                thisSymEntry->second.expression = nullptr;
1138            }
1139            thisSymEntry->second.base = false;
1140            thisSymEntry->second.snapshot = true;
1141            stack.pop();
1142            if (!stack.empty())
1143            {
1144                // put to place in parent expression
1145                StackEntry& parentStackEntry = stack.top();
1146                AsmExpression* parentExpr = parentStackEntry.entry->second.expression;
1147                parentExpr->args[parentStackEntry.argIndex].symbol = thisSymEntry;
1148                parentExpr->ops[parentStackEntry.opIndex] = AsmExprOp::ARG_SYMBOL;
1149            }
1150            else
1151            {
1152                // last we return it
1153                outSymEntry = thisSymEntry;
1154                break;
1155            }
1156        }
1157    }
1158    return good;
1159}
1160
1161// routine that call main makeSymbolSnapshot with error handling
1162bool AsmExpression::makeSymbolSnapshot(Assembler& assembler,
1163           const AsmSymbolEntry& symEntry, AsmSymbolEntry*& outSymEntry,
1164           const AsmSourcePos* parentExprSourcePos)
1165{
1166    TempSymbolSnapshotMap symbolSnapshots;
1167    bool good = true;
1168    try
1169    {
1170        good = makeSymbolSnapshot(assembler, &symbolSnapshots, symEntry, outSymEntry,
1171                    parentExprSourcePos);
1172        if (good)
1173            for (AsmSymbolEntry* symEntry: symbolSnapshots)
1174                // delete evaluated symbol entries (except output symbol entry)
1175                if (outSymEntry != symEntry && symEntry->second.hasValue)
1176                {
1177                    delete symEntry->second.expression;
1178                    symEntry->second.expression = nullptr;
1179                    delete symEntry;
1180                }
1181                else
1182                    assembler.symbolSnapshots.insert(symEntry);
1183        else // if failed
1184            for (AsmSymbolEntry* symEntry: symbolSnapshots)
1185            {
1186                assembler.symbolSnapshots.erase(symEntry);
1187                delete symEntry->second.expression;
1188                symEntry->second.expression = nullptr;
1189                delete symEntry;
1190            }
1191    }
1192    catch(...)
1193    {
1194        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1195        {
1196            assembler.symbolSnapshots.erase(symEntry);
1197            delete symEntry->second.expression;
1198            symEntry->second.expression = nullptr;
1199            delete symEntry;
1200        }
1201        throw;
1202    }   
1203    return good;
1204}
1205
1206AsmExpression* AsmExpression::createExprToEvaluate(Assembler& assembler) const
1207{
1208    TempSymbolSnapshotMap symbolSnapshots;
1209   
1210    try
1211    {
1212    size_t argsNum = 0;
1213    size_t msgPosNum = 0;
1214    for (AsmExprOp op: ops)
1215        if (AsmExpression::isArg(op))
1216            argsNum++;
1217    else if (operatorWithMessage & (1ULL<<int(op)))
1218        msgPosNum++;
1219    std::unique_ptr<AsmExpression> newExpr(new AsmExpression(
1220            sourcePos, symOccursNum, relativeSymOccurs, ops.size(), ops.data(),
1221            msgPosNum, messagePositions.get(), argsNum, args.get(), false));
1222    argsNum = 0;
1223    bool good = true;
1224    // try to resolve symbols
1225    for (AsmExprOp& op: newExpr->ops)
1226        if (AsmExpression::isArg(op))
1227        {
1228            if (op == AsmExprOp::ARG_SYMBOL) // if
1229            {
1230                AsmExprArg& arg = newExpr->args[argsNum];
1231                AsmSymbolEntry* symEntry = arg.symbol;
1232                if (symEntry!=nullptr && symEntry->second.base)
1233                    // create symbol snapshot if symbol is base
1234                    // only if for regular expression (not base
1235                    good &= newExpr->makeSymbolSnapshot(assembler, &symbolSnapshots,
1236                                *symEntry, symEntry, &sourcePos);
1237                if (symEntry==nullptr || !symEntry->second.hasValue)
1238                {
1239                    // no symbol not found
1240                    std::string errorMsg("Expression have unresolved symbol '");
1241                    errorMsg += symEntry->first.c_str();
1242                    errorMsg += '\'';
1243                    ASMX_NOTGOOD_BY_ERROR(sourcePos, errorMsg.c_str())
1244                }
1245                else
1246                {
1247                    if (symEntry->second.hasValue)
1248                    {
1249                        // resolve only if have symbol have value,
1250                        // but do not that if expression will be base for snapshot
1251                        if (!assembler.isAbsoluteSymbol(symEntry->second))
1252                        {
1253                            newExpr->relativeSymOccurs = true;
1254                            arg.relValue.sectionId = symEntry->second.sectionId;
1255                        }
1256                        arg.relValue.value = symEntry->second.value;
1257                        newExpr->symOccursNum--;
1258                        op = AsmExprOp::ARG_VALUE;
1259                    }
1260                }
1261            }
1262            argsNum++;
1263        }
1264   
1265    if (!good)
1266        return nullptr;
1267    // add expression into symbol occurrences in expressions
1268    for (AsmSymbolEntry* symEntry: symbolSnapshots)
1269    {
1270        if (!symEntry->second.hasValue)
1271            assembler.symbolSnapshots.insert(symEntry);
1272        else
1273        {
1274            // delete symbol snapshoft if have new value
1275            delete symEntry->second.expression;
1276            symEntry->second.expression = nullptr;
1277            delete symEntry;
1278        }
1279    }
1280    symbolSnapshots.clear();
1281    return newExpr.release();
1282    }
1283    catch(...)
1284    {
1285        // delete symbol snapshots if exception occurred
1286        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1287        {
1288            // remove from assembler symbolSnapshots
1289            assembler.symbolSnapshots.erase(symEntry);
1290            // remove this snapshot
1291            delete symEntry->second.expression;
1292            symEntry->second.expression = nullptr;
1293            delete symEntry;
1294        }
1295        throw;
1296    }
1297}
1298
1299AsmExpression* AsmExpression::parse(Assembler& assembler, const char*& linePtr,
1300            bool makeBase, bool dontResolveSymbolsLater)
1301{
1302    struct ConExprOpEntry
1303    {
1304        AsmExprOp op;
1305        cxuint priority;
1306        size_t lineColPos;
1307    };
1308
1309    std::stack<ConExprOpEntry> stack;
1310    std::vector<AsmExprOp> ops;
1311    std::vector<AsmExprArg> args;
1312    std::vector<LineCol> messagePositions;
1313    std::vector<LineCol> outMsgPositions;
1314   
1315    TempSymbolSnapshotMap symbolSnapshots;
1316   
1317    try
1318    {
1319    const char* startString = linePtr;
1320    const char* end = assembler.line + assembler.lineSize;
1321    size_t parenthesisCount = 0;
1322    size_t symOccursNum = 0;
1323    bool good = true;
1324    bool relativeSymOccurs = false;
1325   
1326    // indicate what is expected at current place
1327    enum ExpectedToken
1328    {
1329        XT_FIRST = 0,   // operator or argument
1330        XT_OP = 1,  // expected operator
1331        XT_ARG = 2  // expected argument
1332    };
1333    ExpectedToken expectedToken = XT_FIRST;
1334    std::unique_ptr<AsmExpression> expr(new AsmExpression);
1335    expr->sourcePos = assembler.getSourcePos(startString);
1336   
1337    while (linePtr != end)
1338    {
1339        skipSpacesToEnd(linePtr, end);
1340        if (linePtr == end) break;
1341       
1342        LineCol lineCol = { 0, 0 };
1343        AsmExprOp op = AsmExprOp::NONE;
1344        bool expectedPrimaryExpr = false;
1345        //const size_t oldParenthesisCount = parenthesisCount;
1346        bool doExit = false;
1347       
1348        const char* beforeToken = linePtr;
1349        /* parse expression operator or value/symbol */
1350        switch(*linePtr)
1351        {
1352            case '(':
1353                if (expectedToken == XT_OP)
1354                    ASMX_NOTGOOD_BY_ERROR(linePtr, "Expected operator")
1355                else
1356                {
1357                    expectedToken = XT_FIRST;
1358                    parenthesisCount++;
1359                }
1360                linePtr++;
1361                break;
1362            case ')':
1363                if (expectedToken != XT_OP)
1364                    ASMX_NOTGOOD_BY_ERROR(linePtr, "Expected operator or value or symbol")
1365                else
1366                {
1367                    if (parenthesisCount==0)
1368                    { doExit = true; break; }
1369                    parenthesisCount--;
1370                }
1371                linePtr++;
1372                break;
1373            case '+':
1374                op = (expectedToken == XT_OP) ? AsmExprOp::ADDITION : AsmExprOp::PLUS;
1375                linePtr++;
1376                break;
1377            case '-':
1378                op = (expectedToken == XT_OP) ? AsmExprOp::SUBTRACT : AsmExprOp::NEGATE;
1379                linePtr++;
1380                break;
1381            case '*':
1382                op = AsmExprOp::MULTIPLY;
1383                linePtr++;
1384                break;
1385            case '/':
1386                lineCol = assembler.translatePos(linePtr);
1387                if (linePtr+1 != end && linePtr[1] == '/')
1388                {
1389                    op = AsmExprOp::DIVISION;
1390                    linePtr++;
1391                }
1392                else // standard GNU as signed division
1393                    op = AsmExprOp::SIGNED_DIVISION;
1394                linePtr++;
1395                break;
1396            case '%':
1397                lineCol = assembler.translatePos(linePtr);
1398                if (linePtr+1 != end && linePtr[1] == '%')
1399                {
1400                    op = AsmExprOp::MODULO;
1401                    linePtr++;
1402                }
1403                else // standard GNU as signed modulo
1404                    op = AsmExprOp::SIGNED_MODULO;
1405                linePtr++;
1406                break;
1407            case '&':
1408                if (linePtr+1 != end && linePtr[1] == '&')
1409                {
1410                    op = AsmExprOp::LOGICAL_AND;
1411                    linePtr++;
1412                }
1413                else // standard bitwise AND
1414                    op = AsmExprOp::BIT_AND;
1415                linePtr++;
1416                break;
1417            case '|':
1418                if (linePtr+1 != end && linePtr[1] == '|')
1419                {
1420                    op = AsmExprOp::LOGICAL_OR;
1421                    linePtr++;
1422                }
1423                else // standard bitwise OR
1424                    op = AsmExprOp::BIT_OR;
1425                linePtr++;
1426                break;
1427            case '!':
1428                if (expectedToken == XT_OP) // ORNOT or logical not
1429                {
1430                    if (linePtr+1 != end && linePtr[1] == '=')
1431                    {
1432                        // we have != (inequality operator)
1433                        op = AsmExprOp::NOT_EQUAL;
1434                        linePtr++;
1435                    }
1436                    else
1437                        op = AsmExprOp::BIT_ORNOT;
1438                }
1439                else
1440                    op = AsmExprOp::LOGICAL_NOT;
1441                linePtr++;
1442                break;
1443            case '~':
1444                if (expectedToken != XT_OP)
1445                    op = AsmExprOp::BIT_NOT;
1446                else
1447                    ASMX_NOTGOOD_BY_ERROR(linePtr,
1448                        "Expected non-unary operator, '(', or end of expression")
1449                linePtr++;
1450                break;
1451            case '^':
1452                op = AsmExprOp::BIT_XOR;
1453                linePtr++;
1454                break;
1455            case '<':
1456                if (linePtr+1 != end && linePtr[1] == '<')
1457                {
1458                    lineCol = assembler.translatePos(linePtr);
1459                    op = AsmExprOp::SHIFT_LEFT;
1460                    linePtr++;
1461                }
1462                else if (linePtr+1 != end && linePtr[1] == '>')
1463                {
1464                    op = AsmExprOp::NOT_EQUAL;
1465                    linePtr++;
1466                }
1467                else if (linePtr+1 != end && linePtr[1] == '=')
1468                {
1469                    // less or equal than (signed and unsigned)
1470                    if (linePtr+2 != end && linePtr[2] == '@')
1471                    {
1472                        op = AsmExprOp::BELOW_EQ;
1473                        linePtr++;
1474                    }
1475                    else
1476                        op = AsmExprOp::LESS_EQ;
1477                    linePtr++;
1478                }
1479                // less than (signed and unsigned)
1480                else if (linePtr+1 != end && linePtr[1] == '@')
1481                {
1482                    op = AsmExprOp::BELOW;
1483                    linePtr++;
1484                }
1485                else
1486                    op = AsmExprOp::LESS;
1487                linePtr++;
1488                break;
1489            case '>':
1490                if (linePtr+1 != end && linePtr[1] == '>')
1491                {
1492                    lineCol = assembler.translatePos(linePtr);
1493                    if (linePtr+2 != end && linePtr[2] == '>')
1494                    {
1495                        op = AsmExprOp::SIGNED_SHIFT_RIGHT;
1496                        linePtr++;
1497                    }
1498                    else
1499                        op = AsmExprOp::SHIFT_RIGHT;
1500                    linePtr++;
1501                }
1502                else if (linePtr+1 != end && linePtr[1] == '=')
1503                {
1504                    // greater or equal than (signed and unsigned)
1505                    if (linePtr+2 != end && linePtr[2] == '@')
1506                    {
1507                        op = AsmExprOp::ABOVE_EQ;
1508                        linePtr++;
1509                    }
1510                    else
1511                        op = AsmExprOp::GREATER_EQ;
1512                    linePtr++;
1513                }
1514                // greater than (signed and unsigned)
1515                else if (linePtr+1 != end && linePtr[1] == '@')
1516                {
1517                    op = AsmExprOp::ABOVE;
1518                    linePtr++;
1519                }
1520                else
1521                    op = AsmExprOp::GREATER;
1522                linePtr++;
1523                break;
1524            case '=':
1525                if (linePtr+1 != end && linePtr[1] == '=')
1526                {
1527                    op = AsmExprOp::EQUAL;
1528                    linePtr++;
1529                }
1530                else
1531                    expectedPrimaryExpr = true;
1532                linePtr++;
1533                break;
1534            case '?':
1535                lineCol = assembler.translatePos(linePtr);
1536                op = AsmExprOp::CHOICE_START;
1537                linePtr++;
1538                break;
1539            case ':':
1540                if (linePtr+1==end || linePtr[1]!=':')
1541                {
1542                    op = AsmExprOp::CHOICE;
1543                    linePtr++;
1544                    break;
1545                }
1546                // otherwise try parse symbol
1547            default: // parse symbol or value
1548                if (expectedToken != XT_OP)
1549                {
1550                    ExpectedToken oldExpectedToken = expectedToken;
1551                    expectedToken = XT_OP;
1552                    AsmSymbolEntry* symEntry;
1553                   
1554                    const char* symEndStr = linePtr;
1555                    Assembler::ParseState parseState = assembler.parseSymbol(symEndStr,
1556                                     symEntry, true, dontResolveSymbolsLater);
1557                    if (symEntry!=nullptr && symEntry->second.regRange)
1558                    {
1559                        ASMX_NOTGOOD_BY_ERROR(linePtr, "Expression have register symbol")
1560                        continue;
1561                    }
1562                   
1563                    if (parseState == Assembler::ParseState::FAILED) good = false;
1564                    AsmExprArg arg;
1565                    arg.relValue.sectionId = ASMSECT_ABS;
1566                    if (parseState != Assembler::ParseState::MISSING)
1567                    {
1568                        if (symEntry!=nullptr && symEntry->second.base && !makeBase)
1569                            // create symbol snapshot if symbol is base
1570                            // only if for regular expression (not base
1571                            good &= makeSymbolSnapshot(assembler, &symbolSnapshots,
1572                                      *symEntry, symEntry, &(expr->sourcePos));
1573                        if (symEntry==nullptr ||
1574                            (!symEntry->second.hasValue && dontResolveSymbolsLater))
1575                        {
1576                            // no symbol not found
1577                            std::string errorMsg("Expression have unresolved symbol '");
1578                            errorMsg.append(linePtr, symEndStr);
1579                            errorMsg += '\'';
1580                            ASMX_NOTGOOD_BY_ERROR(linePtr, errorMsg.c_str())
1581                        }
1582                        else
1583                        {
1584                            if (symEntry->second.hasValue && !makeBase)
1585                            {
1586                                // resolve only if have symbol have value,
1587                                // but do not that if expression will be base for snapshot
1588                                if (!assembler.isAbsoluteSymbol(symEntry->second))
1589                                {
1590                                    relativeSymOccurs = true;
1591                                    arg.relValue.sectionId = symEntry->second.sectionId;
1592                                }
1593                                arg.relValue.value = symEntry->second.value;
1594                                args.push_back(arg);
1595                                ops.push_back(AsmExprOp::ARG_VALUE);
1596                            }
1597                            else
1598                            {
1599                                /* add symbol */
1600                                symOccursNum++;
1601                                arg.symbol = symEntry;
1602                                args.push_back(arg);
1603                                ops.push_back(AsmExprOp::ARG_SYMBOL);
1604                            }
1605                        }
1606                        linePtr = symEndStr;
1607                    }
1608                    else if (parenthesisCount != 0 || (*linePtr >= '0' &&
1609                            *linePtr <= '9') || *linePtr == '\'')
1610                    {
1611                        // other we try to parse number
1612                        const char* oldStr = linePtr;
1613                        if (!assembler.parseLiteral(arg.value, linePtr))
1614                        {
1615                            arg.value = 0;
1616                            if (linePtr != end && oldStr == linePtr)
1617                                // skip one character when end is in this same place
1618                                // (avoids infinity loops)
1619                                linePtr++;
1620                            good = false;
1621                        }
1622                        args.push_back(arg);
1623                        ops.push_back(AsmExprOp::ARG_VALUE);
1624                    }
1625                    else
1626                    {
1627                        // otherwise we finish parsing
1628                        expectedToken = oldExpectedToken;
1629                        doExit = true; break;
1630                    }
1631                }
1632                else
1633                {
1634                    // otherwise we exit if no left parenthesis
1635                    if (parenthesisCount == 0)
1636                    { doExit = true; break; }
1637                    else
1638                    {
1639                        linePtr++;
1640                        ASMX_NOTGOOD_BY_ERROR(linePtr, "Garbages at end of expression")
1641                    }
1642                }
1643        }
1644       
1645        if (op != AsmExprOp::NONE && !isUnaryOp(op) && expectedToken != XT_OP)
1646        {
1647            expectedPrimaryExpr = true;
1648            op = AsmExprOp::NONE;
1649        }
1650        // when no argument before binary/ternary operator
1651        if (expectedPrimaryExpr)
1652        {
1653            ASMX_NOTGOOD_BY_ERROR(beforeToken,
1654                     "Expected primary expression before operator")
1655            continue;
1656        }
1657       
1658        // determine what is next expected
1659        if (op != AsmExprOp::NONE && !isUnaryOp(op))
1660            expectedToken = (expectedToken == XT_OP) ? XT_ARG : XT_OP;
1661       
1662        //afterParenthesis = (oldParenthesisCount < parenthesisCount);
1663        const size_t lineColPos = (lineCol.lineNo!=0) ? messagePositions.size() : SIZE_MAX;
1664        if (lineCol.lineNo!=0)
1665            messagePositions.push_back(lineCol);
1666       
1667        if (op != AsmExprOp::NONE)
1668        {
1669            // if operator
1670            const bool unaryOp = isUnaryOp(op);
1671            const cxuint priority = (parenthesisCount<<3) +
1672                        asmOpPrioritiesTbl[cxuint(op)];
1673           
1674            if (op == AsmExprOp::CHOICE)
1675            {
1676                /* second part of choice */
1677                while (!stack.empty())
1678                {
1679                    const ConExprOpEntry& entry = stack.top();
1680                    if (priority > entry.priority || (priority == entry.priority &&
1681                        entry.op == AsmExprOp::CHOICE_START))
1682                        break;
1683                    if (entry.op != AsmExprOp::PLUS)
1684                        ops.push_back(entry.op);
1685                    if (entry.lineColPos != SIZE_MAX && entry.op != AsmExprOp::CHOICE_START)
1686                        outMsgPositions.push_back(messagePositions[entry.lineColPos]);
1687                    stack.pop();
1688                }
1689                if (stack.empty())
1690                {
1691                    linePtr--; // go back to ':'
1692                    expectedToken = XT_OP;
1693                    doExit = true;
1694                    break;
1695                }
1696                else if (stack.top().op != AsmExprOp::CHOICE_START ||
1697                        stack.top().priority != priority)
1698                {
1699                    // not found
1700                    ASMX_NOTGOOD_BY_ERROR(beforeToken, "Missing '?' before ':'")
1701                    continue; // do noy change stack and them entries
1702                }
1703                ConExprOpEntry& entry = stack.top();
1704                entry.op = AsmExprOp::CHOICE;
1705                entry.lineColPos = SIZE_MAX;
1706            }
1707            else
1708            {
1709                while (!stack.empty())
1710                {
1711                    const ConExprOpEntry& entry = stack.top();
1712                    if (priority +
1713                        /* because ?: is computed from right to left we adds 1 to priority
1714                         * to force put new node higher than left node */
1715                        (op == AsmExprOp::CHOICE_START) + unaryOp > entry.priority)
1716                        break;
1717                    if (entry.op == AsmExprOp::CHOICE_START)
1718                    {
1719                        // unfinished choice
1720                        stack.pop();
1721                        ASMX_NOTGOOD_BY_ERROR(messagePositions[entry.lineColPos],
1722                                 "Missing ':' for '?'")
1723                        break;
1724                    }
1725                    if (entry.op != AsmExprOp::PLUS)
1726                        ops.push_back(entry.op);
1727                    if (entry.lineColPos != SIZE_MAX && entry.op != AsmExprOp::CHOICE_START)
1728                        outMsgPositions.push_back(messagePositions[entry.lineColPos]);
1729                    stack.pop();
1730                }
1731                stack.push({ op, priority, lineColPos });
1732            }
1733        }
1734       
1735        if (doExit) // exit from parsing
1736            break;
1737    }
1738    if (parenthesisCount != 0) // print error
1739        ASMX_NOTGOOD_BY_ERROR(linePtr, "Missing ')'")
1740    if (expectedToken != XT_OP)
1741    {
1742        if (!ops.empty() || !stack.empty())
1743            ASMX_NOTGOOD_BY_ERROR(linePtr, "Unterminated expression")
1744    }
1745    else
1746    {
1747        while (!stack.empty())
1748        {
1749            const ConExprOpEntry& entry = stack.top();
1750            if (entry.op == AsmExprOp::CHOICE_START)
1751            {
1752                // unfinished choice
1753                ASMX_NOTGOOD_BY_ERROR(messagePositions[entry.lineColPos],
1754                         "Missing ':' for '?'")
1755                break;
1756            }
1757            if (entry.op != AsmExprOp::PLUS)
1758                ops.push_back(entry.op);
1759            if (entry.lineColPos != SIZE_MAX && entry.op != AsmExprOp::CHOICE_START)
1760                outMsgPositions.push_back(messagePositions[entry.lineColPos]);
1761            stack.pop();
1762        }
1763    }
1764   
1765    if (good)
1766    {
1767        const size_t argsNum = args.size();
1768        // if good, we set symbol occurrences, operators, arguments ...
1769        expr->setParams(symOccursNum, relativeSymOccurs,
1770                  ops.size(), ops.data(), outMsgPositions.size(), outMsgPositions.data(),
1771                  argsNum, args.data(), makeBase);
1772        if (!makeBase)
1773        {
1774            // add expression into symbol occurrences in expressions
1775            // only for non-base expressions
1776            for (size_t i = 0, j = 0; j < argsNum; i++)
1777                if (ops[i] == AsmExprOp::ARG_SYMBOL)
1778                {
1779                    args[j].symbol->second.addOccurrenceInExpr(expr.get(), j, i);
1780                    j++;
1781                }
1782                else if (ops[i]==AsmExprOp::ARG_VALUE)
1783                    j++;
1784        }
1785        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1786        {
1787            if (!symEntry->second.hasValue)
1788                assembler.symbolSnapshots.insert(symEntry);
1789            else
1790            {
1791                // delete symbol snapshoft if have new value
1792                delete symEntry->second.expression;
1793                symEntry->second.expression = nullptr;
1794                delete symEntry;
1795            }
1796        }
1797        symbolSnapshots.clear();
1798        return expr.release();
1799    }
1800    else
1801    {
1802        // delete symbol snapshots if error
1803        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1804        {
1805            delete symEntry->second.expression;
1806            symEntry->second.expression = nullptr;
1807            delete symEntry;
1808        }
1809        return nullptr;
1810    }
1811    }
1812    catch(...)
1813    {
1814        // delete symbol snapshots if exception occurred
1815        for (AsmSymbolEntry* symEntry: symbolSnapshots)
1816        {
1817            // remove from assembler symbolSnapshots
1818            assembler.symbolSnapshots.erase(symEntry);
1819            // remove this snapshot
1820            delete symEntry->second.expression;
1821            symEntry->second.expression = nullptr;
1822            delete symEntry;
1823        }
1824        throw;
1825    }
1826}
1827
1828// go to top in expression from specified operator index (can be used to divide expression)
1829size_t AsmExpression::toTop(size_t opIndex) const
1830{
1831    std::stack<cxbyte> stack;
1832    while (true)
1833    {
1834        AsmExprOp op = ops[opIndex];
1835        if (op==AsmExprOp::ARG_VALUE)
1836        {
1837            while (!stack.empty() && --stack.top()==0)
1838                stack.pop();
1839            if (stack.empty())
1840                break; // is end
1841        }
1842        else // operators
1843            stack.push(isUnaryOp(op) ? 1 : (isBinaryOp(op) ? 2 : 3));
1844        opIndex--;
1845    }
1846    return opIndex;
1847}
1848
1849static const uint32_t acceptedCharsAfterFastExpr =
1850    (1U<<('!'-32)) | (1U<<('%'-32)) | (1U<<('&'-32)) | (1U<<('*'-32)) | (1U<<('!'-32)) |
1851        (1U<<('+'-32)) | (1U<<('-'-32)) | (1U<<('/'-32)) | (1U<<('<'-32)) |
1852        (1U<<('='-32)) | (1U<<('>'-32)) | (1U<<('?'-32));
1853
1854bool AsmExpression::fastExprEvaluate(Assembler& assembler, const char*& linePtr,
1855                        uint64_t& value)
1856{
1857    const char* end = assembler.line + assembler.lineSize;
1858    uint64_t sum = 0;
1859    bool addition = true;
1860    const char* tmpLinePtr = linePtr;
1861    skipSpacesToEnd(tmpLinePtr, end);
1862   
1863    // main loop
1864    while (true)
1865    {
1866        // loop for chain of unary '+' and '-'
1867        while (tmpLinePtr != end && (*tmpLinePtr=='+' || *tmpLinePtr=='-'))
1868        {
1869            if (*tmpLinePtr=='-')
1870                addition = !addition;
1871            skipCharAndSpacesToEnd(tmpLinePtr, end);
1872        }
1873        uint64_t tmp = 0;
1874        if (tmpLinePtr == end || (!isDigit(*tmpLinePtr) && *tmpLinePtr!='\''))
1875            return false;
1876        if (!assembler.parseLiteralNoError(tmp, tmpLinePtr))
1877            return false;
1878        if (tmpLinePtr!=end && (*tmpLinePtr=='f' || *tmpLinePtr=='b'))
1879        {   // if local label
1880            const char* t = tmpLinePtr-1;
1881            while (t!=linePtr-1 && isDigit(*t)) t--;
1882            if (t==linePtr-1 || isSpace(*t)) // if local label
1883                return false;
1884        }
1885        // add or subtract
1886        sum += addition ? tmp : -tmp;
1887        // skip to next '+' or '-'
1888        skipSpacesToEnd(tmpLinePtr, end);
1889        if (tmpLinePtr==end || (*tmpLinePtr!='+' && *tmpLinePtr!='-'))
1890            break; // end
1891        // otherwise we continue
1892        addition = (*tmpLinePtr=='+');
1893        skipCharAndSpacesToEnd(tmpLinePtr, end);
1894    }
1895    if (tmpLinePtr==end ||
1896        // check whether is not other operator
1897        (*tmpLinePtr!='~' && *tmpLinePtr!='^' && *tmpLinePtr!='|' &&
1898        (*tmpLinePtr<32 || *tmpLinePtr>=64 ||
1899        // check whether is not other operator (by checking rest of characters)
1900        ((1U<<(*tmpLinePtr-32)) & acceptedCharsAfterFastExpr)==0)))
1901    {
1902        value = sum;
1903        linePtr = tmpLinePtr;
1904        return true;
1905    }
1906    return false;
1907}
1908
1909bool AsmExpression::fastExprEvaluate(Assembler& assembler, size_t& linePos,
1910                        uint64_t& value)
1911{
1912    const char* linePtr = assembler.line + linePos;
1913    bool res = fastExprEvaluate(assembler, linePtr, value);
1914    linePos = linePtr - assembler.line;
1915    return res;
1916}
Note: See TracBrowser for help on using the repository browser.