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
AcpiDmCheckForSymbolicOpcode(ACPI_PARSE_OBJECT * Op,ACPI_OP_WALK_INFO * Info)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
AcpiDmCloseOperator(ACPI_PARSE_OBJECT * Op)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 *
AcpiDmGetCompoundSymbol(UINT16 AmlOpcode)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
AcpiDmPromoteTarget(ACPI_PARSE_OBJECT * Op,ACPI_PARSE_OBJECT * Target)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
AcpiDmIsValidTarget(ACPI_PARSE_OBJECT * Target)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
AcpiDmIsTargetAnOperand(ACPI_PARSE_OBJECT * Target,ACPI_PARSE_OBJECT * Operand,BOOLEAN TopLevel)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