1 /*******************************************************************************
2 *
3 * Module Name: dmcstyle - Support for C-style operator disassembly
4 *
5 ******************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "acparser.h"
47 #include "amlcode.h"
48 #include "acdebug.h"
49
50
51 #define _COMPONENT ACPI_CA_DEBUGGER
52 ACPI_MODULE_NAME ("dmcstyle")
53
54
55 /* Local prototypes */
56
57 static char *
58 AcpiDmGetCompoundSymbol (
59 UINT16 AslOpcode);
60
61 static void
62 AcpiDmPromoteTarget (
63 ACPI_PARSE_OBJECT *Op,
64 ACPI_PARSE_OBJECT *Target);
65
66 static BOOLEAN
67 AcpiDmIsValidTarget (
68 ACPI_PARSE_OBJECT *Op);
69
70 static BOOLEAN
71 AcpiDmIsTargetAnOperand (
72 ACPI_PARSE_OBJECT *Target,
73 ACPI_PARSE_OBJECT *Operand,
74 BOOLEAN TopLevel);
75
76
77 /*******************************************************************************
78 *
79 * FUNCTION: AcpiDmCheckForSymbolicOpcode
80 *
81 * PARAMETERS: Op - Current parse object
82 * Walk - Current parse tree walk info
83 *
84 * RETURN: TRUE if opcode can be converted to symbolic, FALSE otherwise
85 *
86 * DESCRIPTION: This is the main code that implements disassembly of AML code
87 * to C-style operators. Called during descending phase of the
88 * parse tree walk.
89 *
90 ******************************************************************************/
91
92 BOOLEAN
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 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
219
220 /* Save symbol string in the next child (not peer) */
221
222 Child2 = AcpiPsGetArg (Child1, 0);
223 if (!Child2)
224 {
225 return (FALSE);
226 }
227
228 Child2->Common.OperatorSymbol = OperatorSymbol;
229 return (TRUE);
230
231 case AML_INDEX_OP:
232 /*
233 * Check for constant source operand. Note: although technically
234 * legal syntax, the iASL compiler does not support this with
235 * the symbolic operators for Index(). It doesn't make sense to
236 * use Index() with a constant anyway.
237 */
238 if ((Child1->Common.AmlOpcode == AML_STRING_OP) ||
239 (Child1->Common.AmlOpcode == AML_BUFFER_OP) ||
240 (Child1->Common.AmlOpcode == AML_PACKAGE_OP) ||
241 (Child1->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
242 {
243 Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
244 return (FALSE);
245 }
246
247 /* Index operator is [] */
248
249 Child1->Common.OperatorSymbol = " [";
250 Child2->Common.OperatorSymbol = "]";
251 break;
252
253 /* Unary operators */
254
255 case AML_DECREMENT_OP:
256 OperatorSymbol = "--";
257 break;
258
259 case AML_INCREMENT_OP:
260 OperatorSymbol = "++";
261 break;
262
263 case AML_BIT_NOT_OP:
264 case AML_STORE_OP:
265 OperatorSymbol = NULL;
266 break;
267
268 default:
269 return (FALSE);
270 }
271
272 if (Child1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
273 {
274 return (TRUE);
275 }
276
277 /*
278 * This is the key to how the disassembly of the C-style operators
279 * works. We save the operator symbol in the first child, thus
280 * deferring symbol output until after the first operand has been
281 * emitted.
282 */
283 if (!Child1->Common.OperatorSymbol)
284 {
285 Child1->Common.OperatorSymbol = OperatorSymbol;
286 }
287
288 /*
289 * Check for a valid target as the 3rd (or sometimes 2nd) operand
290 *
291 * Compound assignment operator support:
292 * Attempt to optimize constructs of the form:
293 * Add (Local1, 0xFF, Local1)
294 * to:
295 * Local1 += 0xFF
296 *
297 * Only the math operators and Store() have a target.
298 * Logicals have no target.
299 */
300 switch (Op->Common.AmlOpcode)
301 {
302 case AML_ADD_OP:
303 case AML_SUBTRACT_OP:
304 case AML_MULTIPLY_OP:
305 case AML_DIVIDE_OP:
306 case AML_MOD_OP:
307 case AML_SHIFT_LEFT_OP:
308 case AML_SHIFT_RIGHT_OP:
309 case AML_BIT_AND_OP:
310 case AML_BIT_OR_OP:
311 case AML_BIT_XOR_OP:
312
313 /* Target is 3rd operand */
314
315 Target = Child2->Common.Next;
316 if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
317 {
318 /*
319 * Divide has an extra target operand (Remainder).
320 * If this extra target is specified, it cannot be converted
321 * to a C-style operator
322 */
323 if (AcpiDmIsValidTarget (Target))
324 {
325 Child1->Common.OperatorSymbol = NULL;
326 return (FALSE);
327 }
328
329 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
330 Target = Target->Common.Next;
331 }
332
333 /* Parser should ensure there is at least a placeholder target */
334
335 if (!Target)
336 {
337 return (FALSE);
338 }
339
340 if (!AcpiDmIsValidTarget (Target))
341 {
342 /* Not a valid target (placeholder only, from parser) */
343 break;
344 }
345
346 /*
347 * Promote the target up to the first child in the parse
348 * tree. This is done because the target will be output
349 * first, in the form:
350 * <Target> = Operands...
351 */
352 AcpiDmPromoteTarget (Op, Target);
353
354 /* Check operands for conversion to a "Compound Assignment" */
355
356 switch (Op->Common.AmlOpcode)
357 {
358 /* Commutative operators */
359
360 case AML_ADD_OP:
361 case AML_MULTIPLY_OP:
362 case AML_BIT_AND_OP:
363 case AML_BIT_OR_OP:
364 case AML_BIT_XOR_OP:
365 /*
366 * For the commutative operators, we can convert to a
367 * compound statement only if at least one (either) operand
368 * is the same as the target.
369 *
370 * Add (A, B, A) --> A += B
371 * Add (B, A, A) --> A += B
372 * Add (B, C, A) --> A = (B + C)
373 */
374 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) ||
375 (AcpiDmIsTargetAnOperand (Target, Child2, TRUE)))
376 {
377 Target->Common.OperatorSymbol =
378 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
379
380 /* Convert operator to compound assignment */
381
382 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
383 Child1->Common.OperatorSymbol = NULL;
384 return (TRUE);
385 }
386 break;
387
388 /* Non-commutative operators */
389
390 case AML_SUBTRACT_OP:
391 case AML_DIVIDE_OP:
392 case AML_MOD_OP:
393 case AML_SHIFT_LEFT_OP:
394 case AML_SHIFT_RIGHT_OP:
395 /*
396 * For the non-commutative operators, we can convert to a
397 * compound statement only if the target is the same as the
398 * first operand.
399 *
400 * Subtract (A, B, A) --> A -= B
401 * Subtract (B, A, A) --> A = (B - A)
402 */
403 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)))
404 {
405 Target->Common.OperatorSymbol =
406 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
407
408 /* Convert operator to compound assignment */
409
410 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
411 Child1->Common.OperatorSymbol = NULL;
412 return (TRUE);
413 }
414 break;
415
416 default:
417 break;
418 }
419
420 /*
421 * If we are within a C-style expression, emit an extra open
422 * paren. Implemented by examining the parent op.
423 */
424 switch (Op->Common.Parent->Common.AmlOpcode)
425 {
426 case AML_ADD_OP:
427 case AML_SUBTRACT_OP:
428 case AML_MULTIPLY_OP:
429 case AML_DIVIDE_OP:
430 case AML_MOD_OP:
431 case AML_SHIFT_LEFT_OP:
432 case AML_SHIFT_RIGHT_OP:
433 case AML_BIT_AND_OP:
434 case AML_BIT_OR_OP:
435 case AML_BIT_XOR_OP:
436 case AML_LAND_OP:
437 case AML_LEQUAL_OP:
438 case AML_LGREATER_OP:
439 case AML_LLESS_OP:
440 case AML_LOR_OP:
441
442 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
443 AcpiOsPrintf ("(");
444 break;
445
446 default:
447 break;
448 }
449
450 /* Normal output for ASL/AML operators with a target operand */
451
452 Target->Common.OperatorSymbol = " = (";
453 return (TRUE);
454
455 /* Binary operators, no parens */
456
457 case AML_DECREMENT_OP:
458 case AML_INCREMENT_OP:
459 return (TRUE);
460
461 case AML_INDEX_OP:
462
463 /* Target is optional, 3rd operand */
464
465 Target = Child2->Common.Next;
466 if (AcpiDmIsValidTarget (Target))
467 {
468 AcpiDmPromoteTarget (Op, Target);
469
470 if (!Target->Common.OperatorSymbol)
471 {
472 Target->Common.OperatorSymbol = " = ";
473 }
474 }
475 return (TRUE);
476
477 case AML_STORE_OP:
478 /*
479 * Target is the 2nd operand.
480 * We know the target is valid, it is not optional.
481 * In the parse tree, simply swap the target with the
482 * source so that the target is processed first.
483 */
484 Target = Child1->Common.Next;
485 if (!Target)
486 {
487 return (FALSE);
488 }
489
490 AcpiDmPromoteTarget (Op, Target);
491 if (!Target->Common.OperatorSymbol)
492 {
493 Target->Common.OperatorSymbol = " = ";
494 }
495 return (TRUE);
496
497 case AML_BIT_NOT_OP:
498
499 /* Target is optional, 2nd operand */
500
501 Target = Child1->Common.Next;
502 if (!Target)
503 {
504 return (FALSE);
505 }
506
507 if (AcpiDmIsValidTarget (Target))
508 {
509 /* Valid target, not a placeholder */
510
511 AcpiDmPromoteTarget (Op, Target);
512 Target->Common.OperatorSymbol = " = ~";
513 }
514 else
515 {
516 /* No target. Emit this prefix operator immediately */
517
518 AcpiOsPrintf ("~");
519 }
520 return (TRUE);
521
522 default:
523 break;
524 }
525
526 /*
527 * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens
528 * output here. We also need to check the parent to see if this op
529 * is part of a compound test (!=, >=, <=).
530 */
531 if ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) ||
532 ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) &&
533 (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)))
534 {
535 /* Do Nothing. Paren already generated */
536 return (TRUE);
537 }
538
539 /* All other operators, emit an open paren */
540
541 AcpiOsPrintf ("(");
542 return (TRUE);
543 }
544
545
546 /*******************************************************************************
547 *
548 * FUNCTION: AcpiDmCloseOperator
549 *
550 * PARAMETERS: Op - Current parse object
551 *
552 * RETURN: None
553 *
554 * DESCRIPTION: Closes an operator by adding a closing parentheses if and
555 * when necessary. Called during ascending phase of the
556 * parse tree walk.
557 *
558 ******************************************************************************/
559
560 void
AcpiDmCloseOperator(ACPI_PARSE_OBJECT * Op)561 AcpiDmCloseOperator (
562 ACPI_PARSE_OBJECT *Op)
563 {
564 BOOLEAN IsCStyleOp = FALSE;
565
566 /* Always emit paren if ASL+ disassembly disabled */
567
568 if (!AcpiGbl_CstyleDisassembly)
569 {
570 AcpiOsPrintf (")");
571 return;
572 }
573
574 /* Check if we need to add an additional closing paren */
575
576 switch (Op->Common.AmlOpcode)
577 {
578 case AML_ADD_OP:
579 case AML_SUBTRACT_OP:
580 case AML_MULTIPLY_OP:
581 case AML_DIVIDE_OP:
582 case AML_MOD_OP:
583 case AML_SHIFT_LEFT_OP:
584 case AML_SHIFT_RIGHT_OP:
585 case AML_BIT_AND_OP:
586 case AML_BIT_OR_OP:
587 case AML_BIT_XOR_OP:
588 case AML_LAND_OP:
589 case AML_LEQUAL_OP:
590 case AML_LGREATER_OP:
591 case AML_LLESS_OP:
592 case AML_LOR_OP:
593
594 /* Emit paren only if this is not a compound assignment */
595
596 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT)
597 {
598 return;
599 }
600
601 /* Emit extra close paren for assignment within an expression */
602
603 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
604 {
605 AcpiOsPrintf (")");
606 }
607
608 IsCStyleOp = TRUE;
609 break;
610
611 case AML_INDEX_OP:
612
613 /* This is case for unsupported Index() source constants */
614
615 if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
616 {
617 AcpiOsPrintf (")");
618 }
619 return;
620
621 /* No need for parens for these */
622
623 case AML_DECREMENT_OP:
624 case AML_INCREMENT_OP:
625 case AML_LNOT_OP:
626 case AML_BIT_NOT_OP:
627 case AML_STORE_OP:
628 return;
629
630 default:
631
632 /* Always emit paren for non-ASL+ operators */
633 break;
634 }
635
636 /*
637 * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens
638 * output here. We also need to check the parent to see if this op
639 * is part of a compound test (!=, >=, <=).
640 */
641 if (IsCStyleOp &&
642 ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) ||
643 ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) &&
644 (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX))))
645 {
646 return;
647 }
648
649 AcpiOsPrintf (")");
650 return;
651 }
652
653
654 /*******************************************************************************
655 *
656 * FUNCTION: AcpiDmGetCompoundSymbol
657 *
658 * PARAMETERS: AslOpcode
659 *
660 * RETURN: String containing the compound assignment symbol
661 *
662 * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
663 * return the appropriate operator string.
664 *
665 ******************************************************************************/
666
667 static char *
AcpiDmGetCompoundSymbol(UINT16 AmlOpcode)668 AcpiDmGetCompoundSymbol (
669 UINT16 AmlOpcode)
670 {
671 char *Symbol;
672
673
674 switch (AmlOpcode)
675 {
676 case AML_ADD_OP:
677 Symbol = " += ";
678 break;
679
680 case AML_SUBTRACT_OP:
681 Symbol = " -= ";
682 break;
683
684 case AML_MULTIPLY_OP:
685 Symbol = " *= ";
686 break;
687
688 case AML_DIVIDE_OP:
689 Symbol = " /= ";
690 break;
691
692 case AML_MOD_OP:
693 Symbol = " %= ";
694 break;
695
696 case AML_SHIFT_LEFT_OP:
697 Symbol = " <<= ";
698 break;
699
700 case AML_SHIFT_RIGHT_OP:
701 Symbol = " >>= ";
702 break;
703
704 case AML_BIT_AND_OP:
705 Symbol = " &= ";
706 break;
707
708 case AML_BIT_OR_OP:
709 Symbol = " |= ";
710 break;
711
712 case AML_BIT_XOR_OP:
713 Symbol = " ^= ";
714 break;
715
716 default:
717
718 /* No operator string for all other opcodes */
719
720 return (NULL);
721 }
722
723 return (Symbol);
724 }
725
726
727 /*******************************************************************************
728 *
729 * FUNCTION: AcpiDmPromoteTarget
730 *
731 * PARAMETERS: Op - Operator parse object
732 * Target - Target associate with the Op
733 *
734 * RETURN: None
735 *
736 * DESCRIPTION: Transform the parse tree by moving the target up to the first
737 * child of the Op.
738 *
739 ******************************************************************************/
740
741 static void
AcpiDmPromoteTarget(ACPI_PARSE_OBJECT * Op,ACPI_PARSE_OBJECT * Target)742 AcpiDmPromoteTarget (
743 ACPI_PARSE_OBJECT *Op,
744 ACPI_PARSE_OBJECT *Target)
745 {
746 ACPI_PARSE_OBJECT *Child;
747
748
749 /* Link target directly to the Op as first child */
750
751 Child = Op->Common.Value.Arg;
752 Op->Common.Value.Arg = Target;
753 Target->Common.Next = Child;
754
755 /* Find the last peer, it is linked to the target. Unlink it. */
756
757 while (Child->Common.Next != Target)
758 {
759 Child = Child->Common.Next;
760 }
761
762 Child->Common.Next = NULL;
763 }
764
765
766 /*******************************************************************************
767 *
768 * FUNCTION: AcpiDmIsValidTarget
769 *
770 * PARAMETERS: Target - Target Op from the parse tree
771 *
772 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder
773 * Op that was inserted by the parser.
774 *
775 * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
776 * In other words, determine if the optional target is used or
777 * not. Note: If Target is NULL, something is seriously wrong,
778 * probably with the parse tree.
779 *
780 ******************************************************************************/
781
782 static BOOLEAN
AcpiDmIsValidTarget(ACPI_PARSE_OBJECT * Target)783 AcpiDmIsValidTarget (
784 ACPI_PARSE_OBJECT *Target)
785 {
786
787 if (!Target)
788 {
789 return (FALSE);
790 }
791
792 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
793 (Target->Common.Value.Arg == NULL))
794 {
795 return (FALSE);
796 }
797
798 return (TRUE);
799 }
800
801
802 /*******************************************************************************
803 *
804 * FUNCTION: AcpiDmIsTargetAnOperand
805 *
806 * PARAMETERS: Target - Target associated with the expression
807 * Operand - An operand associated with expression
808 *
809 * RETURN: TRUE if expression can be converted to a compound assignment.
810 * FALSE otherwise.
811 *
812 * DESCRIPTION: Determine if the Target duplicates the operand, in order to
813 * detect if the expression can be converted to a compound
814 * assigment. (+=, *=, etc.)
815 *
816 ******************************************************************************/
817
818 static BOOLEAN
AcpiDmIsTargetAnOperand(ACPI_PARSE_OBJECT * Target,ACPI_PARSE_OBJECT * Operand,BOOLEAN TopLevel)819 AcpiDmIsTargetAnOperand (
820 ACPI_PARSE_OBJECT *Target,
821 ACPI_PARSE_OBJECT *Operand,
822 BOOLEAN TopLevel)
823 {
824 const ACPI_OPCODE_INFO *OpInfo;
825 BOOLEAN Same;
826
827
828 /*
829 * Opcodes must match. Note: ignoring the difference between nameseg
830 * and namepath for now. May be needed later.
831 */
832 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
833 {
834 return (FALSE);
835 }
836
837 /* Nodes should match, even if they are NULL */
838
839 if (Target->Common.Node != Operand->Common.Node)
840 {
841 return (FALSE);
842 }
843
844 /* Determine if a child exists */
845
846 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
847 if (OpInfo->Flags & AML_HAS_ARGS)
848 {
849 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
850 Operand->Common.Value.Arg, FALSE);
851 if (!Same)
852 {
853 return (FALSE);
854 }
855 }
856
857 /* Check the next peer, as long as we are not at the top level */
858
859 if ((!TopLevel) &&
860 Target->Common.Next)
861 {
862 Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
863 Operand->Common.Next, FALSE);
864 if (!Same)
865 {
866 return (FALSE);
867 }
868 }
869
870 /* Supress the duplicate operand at the top-level */
871
872 if (TopLevel)
873 {
874 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
875 }
876 return (TRUE);
877 }
878