xref: /freebsd/sys/contrib/dev/acpica/components/disassembler/dmcstyle.c (revision 792bbaba989533a1fc93823df1720c8c4aaf0442)
1 /*******************************************************************************
2  *
3  * Module Name: dmcstyle - Support for C-style operator disassembly
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/include/acparser.h>
47 #include <contrib/dev/acpica/include/amlcode.h>
48 #include <contrib/dev/acpica/include/acdebug.h>
49 
50 
51 #define _COMPONENT          ACPI_CA_DEBUGGER
52         ACPI_MODULE_NAME    ("dmcstyle")
53 
54 
55 /* Local prototypes */
56 
57 static 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     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 char *
815 AcpiDmGetCompoundSymbol (
816    UINT16                   AmlOpcode)
817 {
818     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