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