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