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