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