Sync ACPICA with Intel's version 20170224.
[dragonfly.git] / sys / contrib / dev / acpica / source / components / disassembler / dmcstyle.c
blobb1b9ee4b91fbb871994f0c669f6dbca65fb2dbeb
1 /*******************************************************************************
3 * Module Name: dmcstyle - Support for C-style operator disassembly
5 ******************************************************************************/
7 /*
8 * Copyright (C) 2000 - 2017, Intel Corp.
9 * All rights reserved.
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.
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.
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.
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "acparser.h"
47 #include "amlcode.h"
48 #include "acdebug.h"
49 #include "acconvert.h"
51 #ifdef ACPI_DISASSEMBLER
53 #define _COMPONENT ACPI_CA_DEBUGGER
54 ACPI_MODULE_NAME ("dmcstyle")
57 /* Local prototypes */
59 static char *
60 AcpiDmGetCompoundSymbol (
61 UINT16 AslOpcode);
63 static void
64 AcpiDmPromoteTarget (
65 ACPI_PARSE_OBJECT *Op,
66 ACPI_PARSE_OBJECT *Target);
68 static BOOLEAN
69 AcpiDmIsValidTarget (
70 ACPI_PARSE_OBJECT *Op);
72 static BOOLEAN
73 AcpiDmIsTargetAnOperand (
74 ACPI_PARSE_OBJECT *Target,
75 ACPI_PARSE_OBJECT *Operand,
76 BOOLEAN TopLevel);
78 static BOOLEAN
79 AcpiDmIsOptimizationIgnored (
80 ACPI_PARSE_OBJECT *StoreOp,
81 ACPI_PARSE_OBJECT *StoreArgument);
84 /*******************************************************************************
86 * FUNCTION: AcpiDmCheckForSymbolicOpcode
88 * PARAMETERS: Op - Current parse object
89 * Walk - Current parse tree walk info
91 * RETURN: TRUE if opcode can be converted to symbolic, FALSE otherwise
93 * DESCRIPTION: This is the main code that implements disassembly of AML code
94 * to C-style operators. Called during descending phase of the
95 * parse tree walk.
97 ******************************************************************************/
99 BOOLEAN
100 AcpiDmCheckForSymbolicOpcode (
101 ACPI_PARSE_OBJECT *Op,
102 ACPI_OP_WALK_INFO *Info)
104 char *OperatorSymbol = NULL;
105 ACPI_PARSE_OBJECT *Argument1;
106 ACPI_PARSE_OBJECT *Argument2;
107 ACPI_PARSE_OBJECT *Target;
108 ACPI_PARSE_OBJECT *Target2;
111 /* Exit immediately if ASL+ not enabled */
113 if (!AcpiGbl_CstyleDisassembly)
115 return (FALSE);
118 /* Get the first operand */
120 Argument1 = AcpiPsGetArg (Op, 0);
121 if (!Argument1)
123 return (FALSE);
126 /* Get the second operand */
128 Argument2 = Argument1->Common.Next;
130 /* Setup the operator string for this opcode */
132 switch (Op->Common.AmlOpcode)
134 case AML_ADD_OP:
135 OperatorSymbol = " + ";
136 break;
138 case AML_SUBTRACT_OP:
139 OperatorSymbol = " - ";
140 break;
142 case AML_MULTIPLY_OP:
143 OperatorSymbol = " * ";
144 break;
146 case AML_DIVIDE_OP:
147 OperatorSymbol = " / ";
148 break;
150 case AML_MOD_OP:
151 OperatorSymbol = " % ";
152 break;
154 case AML_SHIFT_LEFT_OP:
155 OperatorSymbol = " << ";
156 break;
158 case AML_SHIFT_RIGHT_OP:
159 OperatorSymbol = " >> ";
160 break;
162 case AML_BIT_AND_OP:
163 OperatorSymbol = " & ";
164 break;
166 case AML_BIT_OR_OP:
167 OperatorSymbol = " | ";
168 break;
170 case AML_BIT_XOR_OP:
171 OperatorSymbol = " ^ ";
172 break;
174 /* Logical operators, no target */
176 case AML_LOGICAL_AND_OP:
177 OperatorSymbol = " && ";
178 break;
180 case AML_LOGICAL_EQUAL_OP:
181 OperatorSymbol = " == ";
182 break;
184 case AML_LOGICAL_GREATER_OP:
185 OperatorSymbol = " > ";
186 break;
188 case AML_LOGICAL_LESS_OP:
189 OperatorSymbol = " < ";
190 break;
192 case AML_LOGICAL_OR_OP:
193 OperatorSymbol = " || ";
194 break;
196 case AML_LOGICAL_NOT_OP:
198 * Check for the LNOT sub-opcodes. These correspond to
199 * LNotEqual, LLessEqual, and LGreaterEqual. There are
200 * no actual AML opcodes for these operators.
202 switch (Argument1->Common.AmlOpcode)
204 case AML_LOGICAL_EQUAL_OP:
205 OperatorSymbol = " != ";
206 break;
208 case AML_LOGICAL_GREATER_OP:
209 OperatorSymbol = " <= ";
210 break;
212 case AML_LOGICAL_LESS_OP:
213 OperatorSymbol = " >= ";
214 break;
216 default:
218 /* Unary LNOT case, emit "!" immediately */
220 AcpiOsPrintf ("!");
221 return (TRUE);
224 Argument1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
225 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
227 /* Save symbol string in the next child (not peer) */
229 Argument2 = AcpiPsGetArg (Argument1, 0);
230 if (!Argument2)
232 return (FALSE);
235 Argument2->Common.OperatorSymbol = OperatorSymbol;
236 return (TRUE);
238 case AML_INDEX_OP:
240 * Check for constant source operand. Note: although technically
241 * legal syntax, the iASL compiler does not support this with
242 * the symbolic operators for Index(). It doesn't make sense to
243 * use Index() with a constant anyway.
245 if ((Argument1->Common.AmlOpcode == AML_STRING_OP) ||
246 (Argument1->Common.AmlOpcode == AML_BUFFER_OP) ||
247 (Argument1->Common.AmlOpcode == AML_PACKAGE_OP) ||
248 (Argument1->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP))
250 Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
251 return (FALSE);
254 /* Index operator is [] */
256 Argument1->Common.OperatorSymbol = " [";
257 Argument2->Common.OperatorSymbol = "]";
258 break;
260 /* Unary operators */
262 case AML_DECREMENT_OP:
263 OperatorSymbol = "--";
264 break;
266 case AML_INCREMENT_OP:
267 OperatorSymbol = "++";
268 break;
270 case AML_BIT_NOT_OP:
271 case AML_STORE_OP:
272 OperatorSymbol = NULL;
273 break;
275 default:
276 return (FALSE);
279 if (Argument1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
281 return (TRUE);
285 * This is the key to how the disassembly of the C-style operators
286 * works. We save the operator symbol in the first child, thus
287 * deferring symbol output until after the first operand has been
288 * emitted.
290 if (!Argument1->Common.OperatorSymbol)
292 Argument1->Common.OperatorSymbol = OperatorSymbol;
296 * Check for a valid target as the 3rd (or sometimes 2nd) operand
298 * Compound assignment operator support:
299 * Attempt to optimize constructs of the form:
300 * Add (Local1, 0xFF, Local1)
301 * to:
302 * Local1 += 0xFF
304 * Only the math operators and Store() have a target.
305 * Logicals have no target.
307 switch (Op->Common.AmlOpcode)
309 case AML_ADD_OP:
310 case AML_SUBTRACT_OP:
311 case AML_MULTIPLY_OP:
312 case AML_DIVIDE_OP:
313 case AML_MOD_OP:
314 case AML_SHIFT_LEFT_OP:
315 case AML_SHIFT_RIGHT_OP:
316 case AML_BIT_AND_OP:
317 case AML_BIT_OR_OP:
318 case AML_BIT_XOR_OP:
320 /* Target is 3rd operand */
322 Target = Argument2->Common.Next;
323 if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
325 Target2 = Target->Common.Next;
328 * Divide has an extra target operand (Remainder).
329 * Default behavior is to simply ignore ASL+ conversion
330 * if the remainder target (modulo) is specified.
332 if (!AcpiGbl_DoDisassemblerOptimizations)
334 if (AcpiDmIsValidTarget (Target))
336 Argument1->Common.OperatorSymbol = NULL;
337 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
338 return (FALSE);
341 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
342 Target = Target2;
344 else
347 * Divide has an extra target operand (Remainder).
348 * If both targets are specified, it cannot be converted
349 * to a C-style operator.
351 if (AcpiDmIsValidTarget (Target) &&
352 AcpiDmIsValidTarget (Target2))
354 Argument1->Common.OperatorSymbol = NULL;
355 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
356 return (FALSE);
359 if (AcpiDmIsValidTarget (Target)) /* Only first Target is valid (remainder) */
361 /* Convert the Divide to Modulo */
363 Op->Common.AmlOpcode = AML_MOD_OP;
365 Argument1->Common.OperatorSymbol = " % ";
366 Target2->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
368 else /* Only second Target (quotient) is valid */
370 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
371 Target = Target2;
376 /* Parser should ensure there is at least a placeholder target */
378 if (!Target)
380 return (FALSE);
383 if (!AcpiDmIsValidTarget (Target))
385 /* Not a valid target (placeholder only, from parser) */
386 break;
390 * Promote the target up to the first child in the parse
391 * tree. This is done because the target will be output
392 * first, in the form:
393 * <Target> = Operands...
395 AcpiDmPromoteTarget (Op, Target);
397 /* Check operands for conversion to a "Compound Assignment" */
399 switch (Op->Common.AmlOpcode)
401 /* Commutative operators */
403 case AML_ADD_OP:
404 case AML_MULTIPLY_OP:
405 case AML_BIT_AND_OP:
406 case AML_BIT_OR_OP:
407 case AML_BIT_XOR_OP:
409 * For the commutative operators, we can convert to a
410 * compound statement only if at least one (either) operand
411 * is the same as the target.
413 * Add (A, B, A) --> A += B
414 * Add (B, A, A) --> A += B
415 * Add (B, C, A) --> A = (B + C)
417 if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)) ||
418 (AcpiDmIsTargetAnOperand (Target, Argument2, TRUE)))
420 Target->Common.OperatorSymbol =
421 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
423 /* Convert operator to compound assignment */
425 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
426 Argument1->Common.OperatorSymbol = NULL;
427 return (TRUE);
429 break;
431 /* Non-commutative operators */
433 case AML_SUBTRACT_OP:
434 case AML_DIVIDE_OP:
435 case AML_MOD_OP:
436 case AML_SHIFT_LEFT_OP:
437 case AML_SHIFT_RIGHT_OP:
439 * For the non-commutative operators, we can convert to a
440 * compound statement only if the target is the same as the
441 * first operand.
443 * Subtract (A, B, A) --> A -= B
444 * Subtract (B, A, A) --> A = (B - A)
446 if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)))
448 Target->Common.OperatorSymbol =
449 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
451 /* Convert operator to compound assignment */
453 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
454 Argument1->Common.OperatorSymbol = NULL;
455 return (TRUE);
457 break;
459 default:
460 break;
464 * If we are within a C-style expression, emit an extra open
465 * paren. Implemented by examining the parent op.
467 switch (Op->Common.Parent->Common.AmlOpcode)
469 case AML_ADD_OP:
470 case AML_SUBTRACT_OP:
471 case AML_MULTIPLY_OP:
472 case AML_DIVIDE_OP:
473 case AML_MOD_OP:
474 case AML_SHIFT_LEFT_OP:
475 case AML_SHIFT_RIGHT_OP:
476 case AML_BIT_AND_OP:
477 case AML_BIT_OR_OP:
478 case AML_BIT_XOR_OP:
479 case AML_LOGICAL_AND_OP:
480 case AML_LOGICAL_EQUAL_OP:
481 case AML_LOGICAL_GREATER_OP:
482 case AML_LOGICAL_LESS_OP:
483 case AML_LOGICAL_OR_OP:
485 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
486 AcpiOsPrintf ("(");
487 break;
489 default:
490 break;
493 /* Normal output for ASL/AML operators with a target operand */
495 Target->Common.OperatorSymbol = " = (";
496 return (TRUE);
498 /* Binary operators, no parens */
500 case AML_DECREMENT_OP:
501 case AML_INCREMENT_OP:
502 return (TRUE);
504 case AML_INDEX_OP:
506 /* Target is optional, 3rd operand */
508 Target = Argument2->Common.Next;
509 if (AcpiDmIsValidTarget (Target))
511 AcpiDmPromoteTarget (Op, Target);
513 if (!Target->Common.OperatorSymbol)
515 Target->Common.OperatorSymbol = " = ";
518 return (TRUE);
520 case AML_STORE_OP:
522 * For Store, the Target is the 2nd operand. We know the target
523 * is valid, because it is not optional.
525 * Ignore any optimizations/folding if flag is set.
526 * Used for iASL/disassembler test suite only.
528 if (AcpiDmIsOptimizationIgnored (Op, Argument1))
530 return (FALSE);
534 * Perform conversion.
535 * In the parse tree, simply swap the target with the
536 * source so that the target is processed first.
538 Target = Argument1->Common.Next;
539 if (!Target)
541 return (FALSE);
544 AcpiDmPromoteTarget (Op, Target);
545 if (!Target->Common.OperatorSymbol)
547 Target->Common.OperatorSymbol = " = ";
549 return (TRUE);
551 case AML_BIT_NOT_OP:
553 /* Target is optional, 2nd operand */
555 Target = Argument1->Common.Next;
556 if (!Target)
558 return (FALSE);
561 if (AcpiDmIsValidTarget (Target))
563 /* Valid target, not a placeholder */
565 AcpiDmPromoteTarget (Op, Target);
566 Target->Common.OperatorSymbol = " = ~";
568 else
570 /* No target. Emit this prefix operator immediately */
572 AcpiOsPrintf ("~");
574 return (TRUE);
576 default:
577 break;
580 /* All other operators, emit an open paren */
582 AcpiOsPrintf ("(");
583 return (TRUE);
587 /*******************************************************************************
589 * FUNCTION: AcpiDmIsOptimizationIgnored
591 * PARAMETERS: StoreOp - Store operator parse object
592 * StoreArgument - Target associate with the Op
594 * RETURN: TRUE if this Store operator should not be converted/removed.
596 * DESCRIPTION: The following function implements "Do not optimize if a
597 * store is immediately followed by a math/bit operator that
598 * has no target".
600 * Function is ignored if DoDisassemblerOptimizations is TRUE.
601 * This is the default, ignore this function.
603 * Disables these types of optimizations, and simply emits
604 * legacy ASL code:
605 * Store (Add (INT1, 4), INT2) --> Add (INT1, 4, INT2)
606 * --> INT2 = INT1 + 4
608 * Store (Not (INT1), INT2) --> Not (INT1, INT2)
609 * --> INT2 = ~INT1
611 * Used only for the ASL test suite. For the test suite, we
612 * don't want to perform some optimizations to ensure binary
613 * compatibility with the generation of the legacy ASL->AML.
614 * In other words, for all test modules we want exactly:
615 * (ASL+ -> AML) == (ASL- -> AML)
617 ******************************************************************************/
619 static BOOLEAN
620 AcpiDmIsOptimizationIgnored (
621 ACPI_PARSE_OBJECT *StoreOp,
622 ACPI_PARSE_OBJECT *StoreArgument)
624 ACPI_PARSE_OBJECT *Argument1;
625 ACPI_PARSE_OBJECT *Argument2;
626 ACPI_PARSE_OBJECT *Target;
629 /* No optimizations/folding for the typical case */
631 if (AcpiGbl_DoDisassemblerOptimizations)
633 return (FALSE);
637 * Only a small subset of ASL/AML operators can be optimized.
638 * Can only optimize/fold if there is no target (or targets)
639 * specified for the operator. And of course, the operator
640 * is surrrounded by a Store() operator.
642 switch (StoreArgument->Common.AmlOpcode)
644 case AML_ADD_OP:
645 case AML_SUBTRACT_OP:
646 case AML_MULTIPLY_OP:
647 case AML_MOD_OP:
648 case AML_SHIFT_LEFT_OP:
649 case AML_SHIFT_RIGHT_OP:
650 case AML_BIT_AND_OP:
651 case AML_BIT_OR_OP:
652 case AML_BIT_XOR_OP:
653 case AML_INDEX_OP:
655 /* These operators have two arguments and one target */
657 Argument1 = StoreArgument->Common.Value.Arg;
658 Argument2 = Argument1->Common.Next;
659 Target = Argument2->Common.Next;
661 if (!AcpiDmIsValidTarget (Target))
663 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
664 return (TRUE);
666 break;
668 case AML_DIVIDE_OP:
670 /* This operator has two arguments and two targets */
672 Argument1 = StoreArgument->Common.Value.Arg;
673 Argument2 = Argument1->Common.Next;
674 Target = Argument2->Common.Next;
676 if (!AcpiDmIsValidTarget (Target) ||
677 !AcpiDmIsValidTarget (Target->Common.Next))
679 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
680 return (TRUE);
682 break;
684 case AML_BIT_NOT_OP:
686 /* This operator has one operand and one target */
688 Argument1 = StoreArgument->Common.Value.Arg;
689 Target = Argument1->Common.Next;
691 if (!AcpiDmIsValidTarget (Target))
693 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
694 return (TRUE);
696 break;
698 default:
699 break;
702 return (FALSE);
706 /*******************************************************************************
708 * FUNCTION: AcpiDmCloseOperator
710 * PARAMETERS: Op - Current parse object
712 * RETURN: None
714 * DESCRIPTION: Closes an operator by adding a closing parentheses if and
715 * when necessary. Called during ascending phase of the
716 * parse tree walk.
718 ******************************************************************************/
720 void
721 AcpiDmCloseOperator (
722 ACPI_PARSE_OBJECT *Op)
725 /* Always emit paren if ASL+ disassembly disabled */
727 if (!AcpiGbl_CstyleDisassembly)
729 AcpiOsPrintf (")");
730 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
731 return;
734 if (Op->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY)
736 AcpiOsPrintf (")");
737 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
738 return;
741 /* Check if we need to add an additional closing paren */
743 switch (Op->Common.AmlOpcode)
745 case AML_ADD_OP:
746 case AML_SUBTRACT_OP:
747 case AML_MULTIPLY_OP:
748 case AML_DIVIDE_OP:
749 case AML_MOD_OP:
750 case AML_SHIFT_LEFT_OP:
751 case AML_SHIFT_RIGHT_OP:
752 case AML_BIT_AND_OP:
753 case AML_BIT_OR_OP:
754 case AML_BIT_XOR_OP:
755 case AML_LOGICAL_AND_OP:
756 case AML_LOGICAL_EQUAL_OP:
757 case AML_LOGICAL_GREATER_OP:
758 case AML_LOGICAL_LESS_OP:
759 case AML_LOGICAL_OR_OP:
761 /* Emit paren only if this is not a compound assignment */
763 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT)
765 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
766 return;
769 /* Emit extra close paren for assignment within an expression */
771 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
773 AcpiOsPrintf (")");
775 break;
777 case AML_INDEX_OP:
779 /* This is case for unsupported Index() source constants */
781 if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
783 AcpiOsPrintf (")");
785 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
786 return;
788 /* No need for parens for these */
790 case AML_DECREMENT_OP:
791 case AML_INCREMENT_OP:
792 case AML_LOGICAL_NOT_OP:
793 case AML_BIT_NOT_OP:
794 case AML_STORE_OP:
795 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
796 return;
798 default:
800 /* Always emit paren for non-ASL+ operators */
801 break;
804 AcpiOsPrintf (")");
805 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
807 return;
811 /*******************************************************************************
813 * FUNCTION: AcpiDmGetCompoundSymbol
815 * PARAMETERS: AslOpcode
817 * RETURN: String containing the compound assignment symbol
819 * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
820 * return the appropriate operator string.
822 ******************************************************************************/
824 static char *
825 AcpiDmGetCompoundSymbol (
826 UINT16 AmlOpcode)
828 char *Symbol;
831 switch (AmlOpcode)
833 case AML_ADD_OP:
834 Symbol = " += ";
835 break;
837 case AML_SUBTRACT_OP:
838 Symbol = " -= ";
839 break;
841 case AML_MULTIPLY_OP:
842 Symbol = " *= ";
843 break;
845 case AML_DIVIDE_OP:
846 Symbol = " /= ";
847 break;
849 case AML_MOD_OP:
850 Symbol = " %= ";
851 break;
853 case AML_SHIFT_LEFT_OP:
854 Symbol = " <<= ";
855 break;
857 case AML_SHIFT_RIGHT_OP:
858 Symbol = " >>= ";
859 break;
861 case AML_BIT_AND_OP:
862 Symbol = " &= ";
863 break;
865 case AML_BIT_OR_OP:
866 Symbol = " |= ";
867 break;
869 case AML_BIT_XOR_OP:
870 Symbol = " ^= ";
871 break;
873 default:
875 /* No operator string for all other opcodes */
877 return (NULL);
880 return (Symbol);
884 /*******************************************************************************
886 * FUNCTION: AcpiDmPromoteTarget
888 * PARAMETERS: Op - Operator parse object
889 * Target - Target associate with the Op
891 * RETURN: None
893 * DESCRIPTION: Transform the parse tree by moving the target up to the first
894 * child of the Op.
896 ******************************************************************************/
898 static void
899 AcpiDmPromoteTarget (
900 ACPI_PARSE_OBJECT *Op,
901 ACPI_PARSE_OBJECT *Target)
903 ACPI_PARSE_OBJECT *Child;
906 /* Link target directly to the Op as first child */
908 Child = Op->Common.Value.Arg;
909 Op->Common.Value.Arg = Target;
910 Target->Common.Next = Child;
912 /* Find the last peer, it is linked to the target. Unlink it. */
914 while (Child->Common.Next != Target)
916 Child = Child->Common.Next;
919 Child->Common.Next = NULL;
923 /*******************************************************************************
925 * FUNCTION: AcpiDmIsValidTarget
927 * PARAMETERS: Target - Target Op from the parse tree
929 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder
930 * Op that was inserted by the parser.
932 * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
933 * In other words, determine if the optional target is used or
934 * not. Note: If Target is NULL, something is seriously wrong,
935 * probably with the parse tree.
937 ******************************************************************************/
939 static BOOLEAN
940 AcpiDmIsValidTarget (
941 ACPI_PARSE_OBJECT *Target)
944 if (!Target)
946 return (FALSE);
949 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
950 (Target->Common.Value.Arg == NULL))
952 return (FALSE);
955 return (TRUE);
959 /*******************************************************************************
961 * FUNCTION: AcpiDmIsTargetAnOperand
963 * PARAMETERS: Target - Target associated with the expression
964 * Operand - An operand associated with expression
966 * RETURN: TRUE if expression can be converted to a compound assignment.
967 * FALSE otherwise.
969 * DESCRIPTION: Determine if the Target duplicates the operand, in order to
970 * detect if the expression can be converted to a compound
971 * assigment. (+=, *=, etc.)
973 ******************************************************************************/
975 static BOOLEAN
976 AcpiDmIsTargetAnOperand (
977 ACPI_PARSE_OBJECT *Target,
978 ACPI_PARSE_OBJECT *Operand,
979 BOOLEAN TopLevel)
981 const ACPI_OPCODE_INFO *OpInfo;
982 BOOLEAN Same;
986 * Opcodes must match. Note: ignoring the difference between nameseg
987 * and namepath for now. May be needed later.
989 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
991 return (FALSE);
994 /* Nodes should match, even if they are NULL */
996 if (Target->Common.Node != Operand->Common.Node)
998 return (FALSE);
1001 /* Determine if a child exists */
1003 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
1004 if (OpInfo->Flags & AML_HAS_ARGS)
1006 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
1007 Operand->Common.Value.Arg, FALSE);
1008 if (!Same)
1010 return (FALSE);
1014 /* Check the next peer, as long as we are not at the top level */
1016 if ((!TopLevel) &&
1017 Target->Common.Next)
1019 Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
1020 Operand->Common.Next, FALSE);
1021 if (!Same)
1023 return (FALSE);
1027 /* Supress the duplicate operand at the top-level */
1029 if (TopLevel)
1031 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1033 return (TRUE);
1036 #endif