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