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