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