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