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