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 <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/acparser.h> 47 #include <contrib/dev/acpica/include/amlcode.h> 48 #include <contrib/dev/acpica/include/acdebug.h> 49 50 51 #define _COMPONENT ACPI_CA_DEBUGGER 52 ACPI_MODULE_NAME ("dmcstyle") 53 54 55 /* Local prototypes */ 56 57 static 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 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 char * 815 AcpiDmGetCompoundSymbol ( 816 UINT16 AmlOpcode) 817 { 818 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