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