Home | History | Annotate | Line # | Download | only in disassembler
dmcstyle.c revision 1.7
      1 /*******************************************************************************
      2  *
      3  * Module Name: dmcstyle - Support for C-style operator disassembly
      4  *
      5  ******************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2017, Intel Corp.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions, and the following disclaimer,
     16  *    without modification.
     17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     18  *    substantially similar to the "NO WARRANTY" disclaimer below
     19  *    ("Disclaimer") and any redistribution must be conditioned upon
     20  *    including a substantially similar Disclaimer requirement for further
     21  *    binary redistribution.
     22  * 3. Neither the names of the above-listed copyright holders nor the names
     23  *    of any contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * Alternatively, this software may be distributed under the terms of the
     27  * GNU General Public License ("GPL") version 2 as published by the Free
     28  * Software Foundation.
     29  *
     30  * NO WARRANTY
     31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     41  * POSSIBILITY OF SUCH DAMAGES.
     42  */
     43 
     44 #include "acpi.h"
     45 #include "accommon.h"
     46 #include "acparser.h"
     47 #include "amlcode.h"
     48 #include "acdebug.h"
     49 
     50 
     51 #define _COMPONENT          ACPI_CA_DEBUGGER
     52         ACPI_MODULE_NAME    ("dmcstyle")
     53 
     54 
     55 /* Local prototypes */
     56 
     57 static const char *
     58 AcpiDmGetCompoundSymbol (
     59    UINT16                   AslOpcode);
     60 
     61 static void
     62 AcpiDmPromoteTarget (
     63     ACPI_PARSE_OBJECT       *Op,
     64     ACPI_PARSE_OBJECT       *Target);
     65 
     66 static BOOLEAN
     67 AcpiDmIsValidTarget (
     68     ACPI_PARSE_OBJECT       *Op);
     69 
     70 static BOOLEAN
     71 AcpiDmIsTargetAnOperand (
     72     ACPI_PARSE_OBJECT       *Target,
     73     ACPI_PARSE_OBJECT       *Operand,
     74     BOOLEAN                 TopLevel);
     75 
     76 static BOOLEAN
     77 AcpiDmIsOptimizationIgnored (
     78     ACPI_PARSE_OBJECT       *StoreOp,
     79     ACPI_PARSE_OBJECT       *StoreArgument);
     80 
     81 
     82 /*******************************************************************************
     83  *
     84  * FUNCTION:    AcpiDmCheckForSymbolicOpcode
     85  *
     86  * PARAMETERS:  Op                  - Current parse object
     87  *              Walk                - Current parse tree walk info
     88  *
     89  * RETURN:      TRUE if opcode can be converted to symbolic, FALSE otherwise
     90  *
     91  * DESCRIPTION: This is the main code that implements disassembly of AML code
     92  *              to C-style operators. Called during descending phase of the
     93  *              parse tree walk.
     94  *
     95  ******************************************************************************/
     96 
     97 BOOLEAN
     98 AcpiDmCheckForSymbolicOpcode (
     99     ACPI_PARSE_OBJECT       *Op,
    100     ACPI_OP_WALK_INFO       *Info)
    101 {
    102     const char              *OperatorSymbol = NULL;
    103     ACPI_PARSE_OBJECT       *Argument1;
    104     ACPI_PARSE_OBJECT       *Argument2;
    105     ACPI_PARSE_OBJECT       *Target;
    106     ACPI_PARSE_OBJECT       *Target2;
    107 
    108 
    109     /* Exit immediately if ASL+ not enabled */
    110 
    111     if (!AcpiGbl_CstyleDisassembly)
    112     {
    113         return (FALSE);
    114     }
    115 
    116     /* Get the first operand */
    117 
    118     Argument1 = AcpiPsGetArg (Op, 0);
    119     if (!Argument1)
    120     {
    121         return (FALSE);
    122     }
    123 
    124     /* Get the second operand */
    125 
    126     Argument2 = Argument1->Common.Next;
    127 
    128     /* Setup the operator string for this opcode */
    129 
    130     switch (Op->Common.AmlOpcode)
    131     {
    132     case AML_ADD_OP:
    133         OperatorSymbol = " + ";
    134         break;
    135 
    136     case AML_SUBTRACT_OP:
    137         OperatorSymbol = " - ";
    138         break;
    139 
    140     case AML_MULTIPLY_OP:
    141         OperatorSymbol = " * ";
    142         break;
    143 
    144     case AML_DIVIDE_OP:
    145         OperatorSymbol = " / ";
    146         break;
    147 
    148     case AML_MOD_OP:
    149         OperatorSymbol = " % ";
    150         break;
    151 
    152     case AML_SHIFT_LEFT_OP:
    153         OperatorSymbol = " << ";
    154         break;
    155 
    156     case AML_SHIFT_RIGHT_OP:
    157         OperatorSymbol = " >> ";
    158         break;
    159 
    160     case AML_BIT_AND_OP:
    161         OperatorSymbol = " & ";
    162         break;
    163 
    164     case AML_BIT_OR_OP:
    165         OperatorSymbol = " | ";
    166         break;
    167 
    168     case AML_BIT_XOR_OP:
    169         OperatorSymbol = " ^ ";
    170         break;
    171 
    172     /* Logical operators, no target */
    173 
    174     case AML_LAND_OP:
    175         OperatorSymbol = " && ";
    176         break;
    177 
    178     case AML_LEQUAL_OP:
    179         OperatorSymbol = " == ";
    180         break;
    181 
    182     case AML_LGREATER_OP:
    183         OperatorSymbol = " > ";
    184         break;
    185 
    186     case AML_LLESS_OP:
    187         OperatorSymbol = " < ";
    188         break;
    189 
    190     case AML_LOR_OP:
    191         OperatorSymbol = " || ";
    192         break;
    193 
    194     case AML_LNOT_OP:
    195         /*
    196          * Check for the LNOT sub-opcodes. These correspond to
    197          * LNotEqual, LLessEqual, and LGreaterEqual. There are
    198          * no actual AML opcodes for these operators.
    199          */
    200         switch (Argument1->Common.AmlOpcode)
    201         {
    202         case AML_LEQUAL_OP:
    203             OperatorSymbol = " != ";
    204             break;
    205 
    206         case AML_LGREATER_OP:
    207             OperatorSymbol = " <= ";
    208             break;
    209 
    210         case AML_LLESS_OP:
    211             OperatorSymbol = " >= ";
    212             break;
    213 
    214         default:
    215 
    216             /* Unary LNOT case, emit "!" immediately */
    217 
    218             AcpiOsPrintf ("!");
    219             return (TRUE);
    220         }
    221 
    222         Argument1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
    223         Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
    224 
    225         /* Save symbol string in the next child (not peer) */
    226 
    227         Argument2 = AcpiPsGetArg (Argument1, 0);
    228         if (!Argument2)
    229         {
    230             return (FALSE);
    231         }
    232 
    233         Argument2->Common.OperatorSymbol = OperatorSymbol;
    234         return (TRUE);
    235 
    236     case AML_INDEX_OP:
    237         /*
    238          * Check for constant source operand. Note: although technically
    239          * legal syntax, the iASL compiler does not support this with
    240          * the symbolic operators for Index(). It doesn't make sense to
    241          * use Index() with a constant anyway.
    242          */
    243         if ((Argument1->Common.AmlOpcode == AML_STRING_OP)  ||
    244             (Argument1->Common.AmlOpcode == AML_BUFFER_OP)  ||
    245             (Argument1->Common.AmlOpcode == AML_PACKAGE_OP) ||
    246             (Argument1->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
    247         {
    248             Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
    249             return (FALSE);
    250         }
    251 
    252         /* Index operator is [] */
    253 
    254         Argument1->Common.OperatorSymbol = " [";
    255         Argument2->Common.OperatorSymbol = "]";
    256         break;
    257 
    258     /* Unary operators */
    259 
    260     case AML_DECREMENT_OP:
    261         OperatorSymbol = "--";
    262         break;
    263 
    264     case AML_INCREMENT_OP:
    265         OperatorSymbol = "++";
    266         break;
    267 
    268     case AML_BIT_NOT_OP:
    269     case AML_STORE_OP:
    270         OperatorSymbol = NULL;
    271         break;
    272 
    273     default:
    274         return (FALSE);
    275     }
    276 
    277     if (Argument1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
    278     {
    279         return (TRUE);
    280     }
    281 
    282     /*
    283      * This is the key to how the disassembly of the C-style operators
    284      * works. We save the operator symbol in the first child, thus
    285      * deferring symbol output until after the first operand has been
    286      * emitted.
    287      */
    288     if (!Argument1->Common.OperatorSymbol)
    289     {
    290         Argument1->Common.OperatorSymbol = OperatorSymbol;
    291     }
    292 
    293     /*
    294      * Check for a valid target as the 3rd (or sometimes 2nd) operand
    295      *
    296      * Compound assignment operator support:
    297      * Attempt to optimize constructs of the form:
    298      *      Add (Local1, 0xFF, Local1)
    299      * to:
    300      *      Local1 += 0xFF
    301      *
    302      * Only the math operators and Store() have a target.
    303      * Logicals have no target.
    304      */
    305     switch (Op->Common.AmlOpcode)
    306     {
    307     case AML_ADD_OP:
    308     case AML_SUBTRACT_OP:
    309     case AML_MULTIPLY_OP:
    310     case AML_DIVIDE_OP:
    311     case AML_MOD_OP:
    312     case AML_SHIFT_LEFT_OP:
    313     case AML_SHIFT_RIGHT_OP:
    314     case AML_BIT_AND_OP:
    315     case AML_BIT_OR_OP:
    316     case AML_BIT_XOR_OP:
    317 
    318         /* Target is 3rd operand */
    319 
    320         Target = Argument2->Common.Next;
    321         if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
    322         {
    323             Target2 = Target->Common.Next;
    324 
    325             /*
    326              * Divide has an extra target operand (Remainder).
    327              * Default behavior is to simply ignore ASL+ conversion
    328              * if the remainder target (modulo) is specified.
    329              */
    330             if (!AcpiGbl_DoDisassemblerOptimizations)
    331             {
    332                 if (AcpiDmIsValidTarget (Target))
    333                 {
    334                     Argument1->Common.OperatorSymbol = NULL;
    335                     Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    336                     return (FALSE);
    337                 }
    338 
    339                 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
    340                 Target = Target2;
    341             }
    342             else
    343             {
    344                 /*
    345                  * Divide has an extra target operand (Remainder).
    346                  * If both targets are specified, it cannot be converted
    347                  * to a C-style operator.
    348                  */
    349                 if (AcpiDmIsValidTarget (Target) &&
    350                     AcpiDmIsValidTarget (Target2))
    351                 {
    352                     Argument1->Common.OperatorSymbol = NULL;
    353                     Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    354                     return (FALSE);
    355                 }
    356 
    357                 if (AcpiDmIsValidTarget (Target)) /* Only first Target is valid (remainder) */
    358                 {
    359                     /* Convert the Divide to Modulo */
    360 
    361                     Op->Common.AmlOpcode = AML_MOD_OP;
    362 
    363                     Argument1->Common.OperatorSymbol = " % ";
    364                     Target2->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
    365                 }
    366                 else /* Only second Target (quotient) is valid */
    367                 {
    368                     Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
    369                     Target = Target2;
    370                 }
    371             }
    372         }
    373 
    374         /* Parser should ensure there is at least a placeholder target */
    375 
    376         if (!Target)
    377         {
    378             return (FALSE);
    379         }
    380 
    381         if (!AcpiDmIsValidTarget (Target))
    382         {
    383             /* Not a valid target (placeholder only, from parser) */
    384             break;
    385         }
    386 
    387         /*
    388          * Promote the target up to the first child in the parse
    389          * tree. This is done because the target will be output
    390          * first, in the form:
    391          *     <Target> = Operands...
    392          */
    393         AcpiDmPromoteTarget (Op, Target);
    394 
    395         /* Check operands for conversion to a "Compound Assignment" */
    396 
    397         switch (Op->Common.AmlOpcode)
    398         {
    399             /* Commutative operators */
    400 
    401         case AML_ADD_OP:
    402         case AML_MULTIPLY_OP:
    403         case AML_BIT_AND_OP:
    404         case AML_BIT_OR_OP:
    405         case AML_BIT_XOR_OP:
    406             /*
    407              * For the commutative operators, we can convert to a
    408              * compound statement only if at least one (either) operand
    409              * is the same as the target.
    410              *
    411              *      Add (A, B, A) --> A += B
    412              *      Add (B, A, A) --> A += B
    413              *      Add (B, C, A) --> A = (B + C)
    414              */
    415             if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)) ||
    416                 (AcpiDmIsTargetAnOperand (Target, Argument2, TRUE)))
    417             {
    418                 Target->Common.OperatorSymbol =
    419                     AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
    420 
    421                 /* Convert operator to compound assignment */
    422 
    423                 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
    424                 Argument1->Common.OperatorSymbol = NULL;
    425                 return (TRUE);
    426             }
    427             break;
    428 
    429             /* Non-commutative operators */
    430 
    431         case AML_SUBTRACT_OP:
    432         case AML_DIVIDE_OP:
    433         case AML_MOD_OP:
    434         case AML_SHIFT_LEFT_OP:
    435         case AML_SHIFT_RIGHT_OP:
    436             /*
    437              * For the non-commutative operators, we can convert to a
    438              * compound statement only if the target is the same as the
    439              * first operand.
    440              *
    441              *      Subtract (A, B, A) --> A -= B
    442              *      Subtract (B, A, A) --> A = (B - A)
    443              */
    444             if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)))
    445             {
    446                 Target->Common.OperatorSymbol =
    447                     AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
    448 
    449                 /* Convert operator to compound assignment */
    450 
    451                 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
    452                 Argument1->Common.OperatorSymbol = NULL;
    453                 return (TRUE);
    454             }
    455             break;
    456 
    457         default:
    458             break;
    459         }
    460 
    461         /*
    462          * If we are within a C-style expression, emit an extra open
    463          * paren. Implemented by examining the parent op.
    464          */
    465         switch (Op->Common.Parent->Common.AmlOpcode)
    466         {
    467         case AML_ADD_OP:
    468         case AML_SUBTRACT_OP:
    469         case AML_MULTIPLY_OP:
    470         case AML_DIVIDE_OP:
    471         case AML_MOD_OP:
    472         case AML_SHIFT_LEFT_OP:
    473         case AML_SHIFT_RIGHT_OP:
    474         case AML_BIT_AND_OP:
    475         case AML_BIT_OR_OP:
    476         case AML_BIT_XOR_OP:
    477         case AML_LAND_OP:
    478         case AML_LEQUAL_OP:
    479         case AML_LGREATER_OP:
    480         case AML_LLESS_OP:
    481         case AML_LOR_OP:
    482 
    483             Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
    484             AcpiOsPrintf ("(");
    485             break;
    486 
    487         default:
    488             break;
    489         }
    490 
    491         /* Normal output for ASL/AML operators with a target operand */
    492 
    493         Target->Common.OperatorSymbol = " = (";
    494         return (TRUE);
    495 
    496     /* Binary operators, no parens */
    497 
    498     case AML_DECREMENT_OP:
    499     case AML_INCREMENT_OP:
    500         return (TRUE);
    501 
    502     case AML_INDEX_OP:
    503 
    504         /* Target is optional, 3rd operand */
    505 
    506         Target = Argument2->Common.Next;
    507         if (AcpiDmIsValidTarget (Target))
    508         {
    509             AcpiDmPromoteTarget (Op, Target);
    510 
    511             if (!Target->Common.OperatorSymbol)
    512             {
    513                 Target->Common.OperatorSymbol = " = ";
    514             }
    515         }
    516         return (TRUE);
    517 
    518     case AML_STORE_OP:
    519         /*
    520          * For Store, the Target is the 2nd operand. We know the target
    521          * is valid, because it is not optional.
    522          *
    523          * Ignore any optimizations/folding if flag is set.
    524          * Used for iASL/disassembler test suite only.
    525          */
    526         if (AcpiDmIsOptimizationIgnored (Op, Argument1))
    527         {
    528             return (FALSE);
    529         }
    530 
    531         /*
    532          * Perform conversion.
    533          * In the parse tree, simply swap the target with the
    534          * source so that the target is processed first.
    535          */
    536         Target = Argument1->Common.Next;
    537         if (!Target)
    538         {
    539             return (FALSE);
    540         }
    541 
    542         AcpiDmPromoteTarget (Op, Target);
    543         if (!Target->Common.OperatorSymbol)
    544         {
    545             Target->Common.OperatorSymbol = " = ";
    546         }
    547         return (TRUE);
    548 
    549     case AML_BIT_NOT_OP:
    550 
    551         /* Target is optional, 2nd operand */
    552 
    553         Target = Argument1->Common.Next;
    554         if (!Target)
    555         {
    556             return (FALSE);
    557         }
    558 
    559         if (AcpiDmIsValidTarget (Target))
    560         {
    561             /* Valid target, not a placeholder */
    562 
    563             AcpiDmPromoteTarget (Op, Target);
    564             Target->Common.OperatorSymbol = " = ~";
    565         }
    566         else
    567         {
    568             /* No target. Emit this prefix operator immediately */
    569 
    570             AcpiOsPrintf ("~");
    571         }
    572         return (TRUE);
    573 
    574     default:
    575         break;
    576     }
    577 
    578     /* All other operators, emit an open paren */
    579 
    580     AcpiOsPrintf ("(");
    581     return (TRUE);
    582 }
    583 
    584 
    585 /*******************************************************************************
    586  *
    587  * FUNCTION:    AcpiDmIsOptimizationIgnored
    588  *
    589  * PARAMETERS:  StoreOp             - Store operator parse object
    590  *              StoreArgument       - Target associate with the Op
    591  *
    592  * RETURN:      TRUE if this Store operator should not be converted/removed.
    593  *
    594  * DESCRIPTION: The following function implements "Do not optimize if a
    595  *              store is immediately followed by a math/bit operator that
    596  *              has no target".
    597  *
    598  *              Function is ignored if DoDisassemblerOptimizations is TRUE.
    599  *              This is the default, ignore this function.
    600  *
    601  *              Disables these types of optimizations, and simply emits
    602  *              legacy ASL code:
    603  *                  Store (Add (INT1, 4), INT2) --> Add (INT1, 4, INT2)
    604  *                                              --> INT2 = INT1 + 4
    605  *
    606  *                  Store (Not (INT1), INT2)    --> Not (INT1, INT2)
    607  *                                              --> INT2 = ~INT1
    608  *
    609  *              Used only for the ASL test suite. For the test suite, we
    610  *              don't want to perform some optimizations to ensure binary
    611  *              compatibility with the generation of the legacy ASL->AML.
    612  *              In other words, for all test modules we want exactly:
    613  *                  (ASL+ -> AML) == (ASL- -> AML)
    614  *
    615  ******************************************************************************/
    616 
    617 static BOOLEAN
    618 AcpiDmIsOptimizationIgnored (
    619     ACPI_PARSE_OBJECT       *StoreOp,
    620     ACPI_PARSE_OBJECT       *StoreArgument)
    621 {
    622     ACPI_PARSE_OBJECT       *Argument1;
    623     ACPI_PARSE_OBJECT       *Argument2;
    624     ACPI_PARSE_OBJECT       *Target;
    625 
    626 
    627     /* No optimizations/folding for the typical case */
    628 
    629     if (AcpiGbl_DoDisassemblerOptimizations)
    630     {
    631         return (FALSE);
    632     }
    633 
    634     /*
    635      * Only a small subset of ASL/AML operators can be optimized.
    636      * Can only optimize/fold if there is no target (or targets)
    637      * specified for the operator. And of course, the operator
    638      * is surrrounded by a Store() operator.
    639      */
    640     switch (StoreArgument->Common.AmlOpcode)
    641     {
    642     case AML_ADD_OP:
    643     case AML_SUBTRACT_OP:
    644     case AML_MULTIPLY_OP:
    645     case AML_MOD_OP:
    646     case AML_SHIFT_LEFT_OP:
    647     case AML_SHIFT_RIGHT_OP:
    648     case AML_BIT_AND_OP:
    649     case AML_BIT_OR_OP:
    650     case AML_BIT_XOR_OP:
    651     case AML_INDEX_OP:
    652 
    653         /* These operators have two arguments and one target */
    654 
    655         Argument1 = StoreArgument->Common.Value.Arg;
    656         Argument2 = Argument1->Common.Next;
    657         Target = Argument2->Common.Next;
    658 
    659         if (!AcpiDmIsValidTarget (Target))
    660         {
    661             StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    662             return (TRUE);
    663         }
    664         break;
    665 
    666     case AML_DIVIDE_OP:
    667 
    668         /* This operator has two arguments and two targets */
    669 
    670         Argument1 = StoreArgument->Common.Value.Arg;
    671         Argument2 = Argument1->Common.Next;
    672         Target = Argument2->Common.Next;
    673 
    674         if (!AcpiDmIsValidTarget (Target) ||
    675             !AcpiDmIsValidTarget (Target->Common.Next))
    676         {
    677             StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    678             return (TRUE);
    679         }
    680         break;
    681 
    682     case AML_BIT_NOT_OP:
    683 
    684         /* This operator has one operand and one target */
    685 
    686         Argument1 = StoreArgument->Common.Value.Arg;
    687         Target = Argument1->Common.Next;
    688 
    689         if (!AcpiDmIsValidTarget (Target))
    690         {
    691             StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    692             return (TRUE);
    693         }
    694         break;
    695 
    696     default:
    697         break;
    698     }
    699 
    700     return (FALSE);
    701 }
    702 
    703 
    704 /*******************************************************************************
    705  *
    706  * FUNCTION:    AcpiDmCloseOperator
    707  *
    708  * PARAMETERS:  Op                  - Current parse object
    709  *
    710  * RETURN:      None
    711  *
    712  * DESCRIPTION: Closes an operator by adding a closing parentheses if and
    713  *              when necessary. Called during ascending phase of the
    714  *              parse tree walk.
    715  *
    716  ******************************************************************************/
    717 
    718 void
    719 AcpiDmCloseOperator (
    720     ACPI_PARSE_OBJECT       *Op)
    721 {
    722 
    723     /* Always emit paren if ASL+ disassembly disabled */
    724 
    725     if (!AcpiGbl_CstyleDisassembly)
    726     {
    727         AcpiOsPrintf (")");
    728         return;
    729     }
    730 
    731     if (Op->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY)
    732     {
    733         AcpiOsPrintf (")");
    734         return;
    735     }
    736 
    737     /* Check if we need to add an additional closing paren */
    738 
    739     switch (Op->Common.AmlOpcode)
    740     {
    741     case AML_ADD_OP:
    742     case AML_SUBTRACT_OP:
    743     case AML_MULTIPLY_OP:
    744     case AML_DIVIDE_OP:
    745     case AML_MOD_OP:
    746     case AML_SHIFT_LEFT_OP:
    747     case AML_SHIFT_RIGHT_OP:
    748     case AML_BIT_AND_OP:
    749     case AML_BIT_OR_OP:
    750     case AML_BIT_XOR_OP:
    751     case AML_LAND_OP:
    752     case AML_LEQUAL_OP:
    753     case AML_LGREATER_OP:
    754     case AML_LLESS_OP:
    755     case AML_LOR_OP:
    756 
    757         /* Emit paren only if this is not a compound assignment */
    758 
    759         if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT)
    760         {
    761             return;
    762         }
    763 
    764         /* Emit extra close paren for assignment within an expression */
    765 
    766         if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
    767         {
    768             AcpiOsPrintf (")");
    769         }
    770         break;
    771 
    772     case AML_INDEX_OP:
    773 
    774         /* This is case for unsupported Index() source constants */
    775 
    776         if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
    777         {
    778             AcpiOsPrintf (")");
    779         }
    780         return;
    781 
    782     /* No need for parens for these */
    783 
    784     case AML_DECREMENT_OP:
    785     case AML_INCREMENT_OP:
    786     case AML_LNOT_OP:
    787     case AML_BIT_NOT_OP:
    788     case AML_STORE_OP:
    789         return;
    790 
    791     default:
    792 
    793         /* Always emit paren for non-ASL+ operators */
    794         break;
    795     }
    796 
    797     AcpiOsPrintf (")");
    798 }
    799 
    800 
    801 /*******************************************************************************
    802  *
    803  * FUNCTION:    AcpiDmGetCompoundSymbol
    804  *
    805  * PARAMETERS:  AslOpcode
    806  *
    807  * RETURN:      String containing the compound assignment symbol
    808  *
    809  * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
    810  *              return the appropriate operator string.
    811  *
    812  ******************************************************************************/
    813 
    814 static const char *
    815 AcpiDmGetCompoundSymbol (
    816    UINT16                   AmlOpcode)
    817 {
    818     const char               *Symbol;
    819 
    820 
    821     switch (AmlOpcode)
    822     {
    823     case AML_ADD_OP:
    824         Symbol = " += ";
    825         break;
    826 
    827     case AML_SUBTRACT_OP:
    828         Symbol = " -= ";
    829         break;
    830 
    831     case AML_MULTIPLY_OP:
    832         Symbol = " *= ";
    833         break;
    834 
    835     case AML_DIVIDE_OP:
    836         Symbol = " /= ";
    837         break;
    838 
    839     case AML_MOD_OP:
    840         Symbol = " %= ";
    841         break;
    842 
    843     case AML_SHIFT_LEFT_OP:
    844         Symbol = " <<= ";
    845         break;
    846 
    847     case AML_SHIFT_RIGHT_OP:
    848         Symbol = " >>= ";
    849         break;
    850 
    851     case AML_BIT_AND_OP:
    852         Symbol = " &= ";
    853         break;
    854 
    855     case AML_BIT_OR_OP:
    856         Symbol = " |= ";
    857         break;
    858 
    859     case AML_BIT_XOR_OP:
    860         Symbol = " ^= ";
    861         break;
    862 
    863     default:
    864 
    865         /* No operator string for all other opcodes */
    866 
    867         return (NULL);
    868     }
    869 
    870     return (Symbol);
    871 }
    872 
    873 
    874 /*******************************************************************************
    875  *
    876  * FUNCTION:    AcpiDmPromoteTarget
    877  *
    878  * PARAMETERS:  Op                  - Operator parse object
    879  *              Target              - Target associate with the Op
    880  *
    881  * RETURN:      None
    882  *
    883  * DESCRIPTION: Transform the parse tree by moving the target up to the first
    884  *              child of the Op.
    885  *
    886  ******************************************************************************/
    887 
    888 static void
    889 AcpiDmPromoteTarget (
    890     ACPI_PARSE_OBJECT       *Op,
    891     ACPI_PARSE_OBJECT       *Target)
    892 {
    893     ACPI_PARSE_OBJECT       *Child;
    894 
    895 
    896     /* Link target directly to the Op as first child */
    897 
    898     Child = Op->Common.Value.Arg;
    899     Op->Common.Value.Arg = Target;
    900     Target->Common.Next = Child;
    901 
    902     /* Find the last peer, it is linked to the target. Unlink it. */
    903 
    904     while (Child->Common.Next != Target)
    905     {
    906         Child = Child->Common.Next;
    907     }
    908 
    909     Child->Common.Next = NULL;
    910 }
    911 
    912 
    913 /*******************************************************************************
    914  *
    915  * FUNCTION:    AcpiDmIsValidTarget
    916  *
    917  * PARAMETERS:  Target              - Target Op from the parse tree
    918  *
    919  * RETURN:      TRUE if the Target is real. FALSE if it is just a placeholder
    920  *              Op that was inserted by the parser.
    921  *
    922  * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
    923  *              In other words, determine if the optional target is used or
    924  *              not. Note: If Target is NULL, something is seriously wrong,
    925  *              probably with the parse tree.
    926  *
    927  ******************************************************************************/
    928 
    929 static BOOLEAN
    930 AcpiDmIsValidTarget (
    931     ACPI_PARSE_OBJECT       *Target)
    932 {
    933 
    934     if (!Target)
    935     {
    936         return (FALSE);
    937     }
    938 
    939     if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
    940         (Target->Common.Value.Arg == NULL))
    941     {
    942         return (FALSE);
    943     }
    944 
    945     return (TRUE);
    946 }
    947 
    948 
    949 /*******************************************************************************
    950  *
    951  * FUNCTION:    AcpiDmIsTargetAnOperand
    952  *
    953  * PARAMETERS:  Target              - Target associated with the expression
    954  *              Operand             - An operand associated with expression
    955  *
    956  * RETURN:      TRUE if expression can be converted to a compound assignment.
    957  *              FALSE otherwise.
    958  *
    959  * DESCRIPTION: Determine if the Target duplicates the operand, in order to
    960  *              detect if the expression can be converted to a compound
    961  *              assigment. (+=, *=, etc.)
    962  *
    963  ******************************************************************************/
    964 
    965 static BOOLEAN
    966 AcpiDmIsTargetAnOperand (
    967     ACPI_PARSE_OBJECT       *Target,
    968     ACPI_PARSE_OBJECT       *Operand,
    969     BOOLEAN                 TopLevel)
    970 {
    971     const ACPI_OPCODE_INFO  *OpInfo;
    972     BOOLEAN                 Same;
    973 
    974 
    975     /*
    976      * Opcodes must match. Note: ignoring the difference between nameseg
    977      * and namepath for now. May be needed later.
    978      */
    979     if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
    980     {
    981         return (FALSE);
    982     }
    983 
    984     /* Nodes should match, even if they are NULL */
    985 
    986     if (Target->Common.Node != Operand->Common.Node)
    987     {
    988         return (FALSE);
    989     }
    990 
    991     /* Determine if a child exists */
    992 
    993     OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
    994     if (OpInfo->Flags & AML_HAS_ARGS)
    995     {
    996         Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
    997             Operand->Common.Value.Arg, FALSE);
    998         if (!Same)
    999         {
   1000             return (FALSE);
   1001         }
   1002     }
   1003 
   1004     /* Check the next peer, as long as we are not at the top level */
   1005 
   1006     if ((!TopLevel) &&
   1007          Target->Common.Next)
   1008     {
   1009         Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
   1010             Operand->Common.Next, FALSE);
   1011         if (!Same)
   1012         {
   1013             return (FALSE);
   1014         }
   1015     }
   1016 
   1017     /* Supress the duplicate operand at the top-level */
   1018 
   1019     if (TopLevel)
   1020     {
   1021         Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
   1022     }
   1023     return (TRUE);
   1024 }
   1025