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