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