1 /******************************************************************************* 2 * 3 * Module Name: dmcstyle - Support for C-style operator disassembly 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2017, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include "acpi.h" 45 #include "accommon.h" 46 #include "acparser.h" 47 #include "amlcode.h" 48 #include "acdebug.h" 49 #include "acconvert.h" 50 51 #ifdef ACPI_DISASSEMBLER 52 53 #define _COMPONENT ACPI_CA_DEBUGGER 54 ACPI_MODULE_NAME ("dmcstyle") 55 56 57 /* Local prototypes */ 58 59 static char * 60 AcpiDmGetCompoundSymbol ( 61 UINT16 AslOpcode); 62 63 static void 64 AcpiDmPromoteTarget ( 65 ACPI_PARSE_OBJECT *Op, 66 ACPI_PARSE_OBJECT *Target); 67 68 static BOOLEAN 69 AcpiDmIsValidTarget ( 70 ACPI_PARSE_OBJECT *Op); 71 72 static BOOLEAN 73 AcpiDmIsTargetAnOperand ( 74 ACPI_PARSE_OBJECT *Target, 75 ACPI_PARSE_OBJECT *Operand, 76 BOOLEAN TopLevel); 77 78 static BOOLEAN 79 AcpiDmIsOptimizationIgnored ( 80 ACPI_PARSE_OBJECT *StoreOp, 81 ACPI_PARSE_OBJECT *StoreArgument); 82 83 84 /******************************************************************************* 85 * 86 * FUNCTION: AcpiDmCheckForSymbolicOpcode 87 * 88 * PARAMETERS: Op - Current parse object 89 * Walk - Current parse tree walk info 90 * 91 * RETURN: TRUE if opcode can be converted to symbolic, FALSE otherwise 92 * 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. 96 * 97 ******************************************************************************/ 98 99 BOOLEAN 100 AcpiDmCheckForSymbolicOpcode ( 101 ACPI_PARSE_OBJECT *Op, 102 ACPI_OP_WALK_INFO *Info) 103 { 104 char *OperatorSymbol = NULL; 105 ACPI_PARSE_OBJECT *Argument1; 106 ACPI_PARSE_OBJECT *Argument2; 107 ACPI_PARSE_OBJECT *Target; 108 ACPI_PARSE_OBJECT *Target2; 109 110 111 /* Exit immediately if ASL+ not enabled */ 112 113 if (!AcpiGbl_CstyleDisassembly) 114 { 115 return (FALSE); 116 } 117 118 /* Get the first operand */ 119 120 Argument1 = AcpiPsGetArg (Op, 0); 121 if (!Argument1) 122 { 123 return (FALSE); 124 } 125 126 /* Get the second operand */ 127 128 Argument2 = Argument1->Common.Next; 129 130 /* Setup the operator string for this opcode */ 131 132 switch (Op->Common.AmlOpcode) 133 { 134 case AML_ADD_OP: 135 OperatorSymbol = " + "; 136 break; 137 138 case AML_SUBTRACT_OP: 139 OperatorSymbol = " - "; 140 break; 141 142 case AML_MULTIPLY_OP: 143 OperatorSymbol = " * "; 144 break; 145 146 case AML_DIVIDE_OP: 147 OperatorSymbol = " / "; 148 break; 149 150 case AML_MOD_OP: 151 OperatorSymbol = " % "; 152 break; 153 154 case AML_SHIFT_LEFT_OP: 155 OperatorSymbol = " << "; 156 break; 157 158 case AML_SHIFT_RIGHT_OP: 159 OperatorSymbol = " >> "; 160 break; 161 162 case AML_BIT_AND_OP: 163 OperatorSymbol = " & "; 164 break; 165 166 case AML_BIT_OR_OP: 167 OperatorSymbol = " | "; 168 break; 169 170 case AML_BIT_XOR_OP: 171 OperatorSymbol = " ^ "; 172 break; 173 174 /* Logical operators, no target */ 175 176 case AML_LOGICAL_AND_OP: 177 OperatorSymbol = " && "; 178 break; 179 180 case AML_LOGICAL_EQUAL_OP: 181 OperatorSymbol = " == "; 182 break; 183 184 case AML_LOGICAL_GREATER_OP: 185 OperatorSymbol = " > "; 186 break; 187 188 case AML_LOGICAL_LESS_OP: 189 OperatorSymbol = " < "; 190 break; 191 192 case AML_LOGICAL_OR_OP: 193 OperatorSymbol = " || "; 194 break; 195 196 case AML_LOGICAL_NOT_OP: 197 /* 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. 201 */ 202 switch (Argument1->Common.AmlOpcode) 203 { 204 case AML_LOGICAL_EQUAL_OP: 205 OperatorSymbol = " != "; 206 break; 207 208 case AML_LOGICAL_GREATER_OP: 209 OperatorSymbol = " <= "; 210 break; 211 212 case AML_LOGICAL_LESS_OP: 213 OperatorSymbol = " >= "; 214 break; 215 216 default: 217 218 /* Unary LNOT case, emit "!" immediately */ 219 220 AcpiOsPrintf ("!"); 221 return (TRUE); 222 } 223 224 Argument1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX; 225 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; 226 227 /* Save symbol string in the next child (not peer) */ 228 229 Argument2 = AcpiPsGetArg (Argument1, 0); 230 if (!Argument2) 231 { 232 return (FALSE); 233 } 234 235 Argument2->Common.OperatorSymbol = OperatorSymbol; 236 return (TRUE); 237 238 case AML_INDEX_OP: 239 /* 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. 244 */ 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)) 249 { 250 Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN; 251 return (FALSE); 252 } 253 254 /* Index operator is [] */ 255 256 Argument1->Common.OperatorSymbol = " ["; 257 Argument2->Common.OperatorSymbol = "]"; 258 break; 259 260 /* Unary operators */ 261 262 case AML_DECREMENT_OP: 263 OperatorSymbol = "--"; 264 break; 265 266 case AML_INCREMENT_OP: 267 OperatorSymbol = "++"; 268 break; 269 270 case AML_BIT_NOT_OP: 271 case AML_STORE_OP: 272 OperatorSymbol = NULL; 273 break; 274 275 default: 276 return (FALSE); 277 } 278 279 if (Argument1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX) 280 { 281 return (TRUE); 282 } 283 284 /* 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. 289 */ 290 if (!Argument1->Common.OperatorSymbol) 291 { 292 Argument1->Common.OperatorSymbol = OperatorSymbol; 293 } 294 295 /* 296 * Check for a valid target as the 3rd (or sometimes 2nd) operand 297 * 298 * Compound assignment operator support: 299 * Attempt to optimize constructs of the form: 300 * Add (Local1, 0xFF, Local1) 301 * to: 302 * Local1 += 0xFF 303 * 304 * Only the math operators and Store() have a target. 305 * Logicals have no target. 306 */ 307 switch (Op->Common.AmlOpcode) 308 { 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: 319 320 /* Target is 3rd operand */ 321 322 Target = Argument2->Common.Next; 323 if (Op->Common.AmlOpcode == AML_DIVIDE_OP) 324 { 325 Target2 = Target->Common.Next; 326 327 /* 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. 331 */ 332 if (!AcpiGbl_DoDisassemblerOptimizations) 333 { 334 if (AcpiDmIsValidTarget (Target)) 335 { 336 Argument1->Common.OperatorSymbol = NULL; 337 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 338 return (FALSE); 339 } 340 341 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 342 Target = Target2; 343 } 344 else 345 { 346 /* 347 * Divide has an extra target operand (Remainder). 348 * If both targets are specified, it cannot be converted 349 * to a C-style operator. 350 */ 351 if (AcpiDmIsValidTarget (Target) && 352 AcpiDmIsValidTarget (Target2)) 353 { 354 Argument1->Common.OperatorSymbol = NULL; 355 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 356 return (FALSE); 357 } 358 359 if (AcpiDmIsValidTarget (Target)) /* Only first Target is valid (remainder) */ 360 { 361 /* Convert the Divide to Modulo */ 362 363 Op->Common.AmlOpcode = AML_MOD_OP; 364 365 Argument1->Common.OperatorSymbol = " % "; 366 Target2->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 367 } 368 else /* Only second Target (quotient) is valid */ 369 { 370 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 371 Target = Target2; 372 } 373 } 374 } 375 376 /* Parser should ensure there is at least a placeholder target */ 377 378 if (!Target) 379 { 380 return (FALSE); 381 } 382 383 if (!AcpiDmIsValidTarget (Target)) 384 { 385 /* Not a valid target (placeholder only, from parser) */ 386 break; 387 } 388 389 /* 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... 394 */ 395 AcpiDmPromoteTarget (Op, Target); 396 397 /* Check operands for conversion to a "Compound Assignment" */ 398 399 switch (Op->Common.AmlOpcode) 400 { 401 /* Commutative operators */ 402 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: 408 /* 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. 412 * 413 * Add (A, B, A) --> A += B 414 * Add (B, A, A) --> A += B 415 * Add (B, C, A) --> A = (B + C) 416 */ 417 if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)) || 418 (AcpiDmIsTargetAnOperand (Target, Argument2, TRUE))) 419 { 420 Target->Common.OperatorSymbol = 421 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode); 422 423 /* Convert operator to compound assignment */ 424 425 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT; 426 Argument1->Common.OperatorSymbol = NULL; 427 return (TRUE); 428 } 429 break; 430 431 /* Non-commutative operators */ 432 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: 438 /* 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. 442 * 443 * Subtract (A, B, A) --> A -= B 444 * Subtract (B, A, A) --> A = (B - A) 445 */ 446 if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE))) 447 { 448 Target->Common.OperatorSymbol = 449 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode); 450 451 /* Convert operator to compound assignment */ 452 453 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT; 454 Argument1->Common.OperatorSymbol = NULL; 455 return (TRUE); 456 } 457 break; 458 459 default: 460 break; 461 } 462 463 /* 464 * If we are within a C-style expression, emit an extra open 465 * paren. Implemented by examining the parent op. 466 */ 467 switch (Op->Common.Parent->Common.AmlOpcode) 468 { 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: 484 485 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT; 486 AcpiOsPrintf ("("); 487 break; 488 489 default: 490 break; 491 } 492 493 /* Normal output for ASL/AML operators with a target operand */ 494 495 Target->Common.OperatorSymbol = " = ("; 496 return (TRUE); 497 498 /* Binary operators, no parens */ 499 500 case AML_DECREMENT_OP: 501 case AML_INCREMENT_OP: 502 return (TRUE); 503 504 case AML_INDEX_OP: 505 506 /* Target is optional, 3rd operand */ 507 508 Target = Argument2->Common.Next; 509 if (AcpiDmIsValidTarget (Target)) 510 { 511 AcpiDmPromoteTarget (Op, Target); 512 513 if (!Target->Common.OperatorSymbol) 514 { 515 Target->Common.OperatorSymbol = " = "; 516 } 517 } 518 return (TRUE); 519 520 case AML_STORE_OP: 521 /* 522 * For Store, the Target is the 2nd operand. We know the target 523 * is valid, because it is not optional. 524 * 525 * Ignore any optimizations/folding if flag is set. 526 * Used for iASL/disassembler test suite only. 527 */ 528 if (AcpiDmIsOptimizationIgnored (Op, Argument1)) 529 { 530 return (FALSE); 531 } 532 533 /* 534 * Perform conversion. 535 * In the parse tree, simply swap the target with the 536 * source so that the target is processed first. 537 */ 538 Target = Argument1->Common.Next; 539 if (!Target) 540 { 541 return (FALSE); 542 } 543 544 AcpiDmPromoteTarget (Op, Target); 545 if (!Target->Common.OperatorSymbol) 546 { 547 Target->Common.OperatorSymbol = " = "; 548 } 549 return (TRUE); 550 551 case AML_BIT_NOT_OP: 552 553 /* Target is optional, 2nd operand */ 554 555 Target = Argument1->Common.Next; 556 if (!Target) 557 { 558 return (FALSE); 559 } 560 561 if (AcpiDmIsValidTarget (Target)) 562 { 563 /* Valid target, not a placeholder */ 564 565 AcpiDmPromoteTarget (Op, Target); 566 Target->Common.OperatorSymbol = " = ~"; 567 } 568 else 569 { 570 /* No target. Emit this prefix operator immediately */ 571 572 AcpiOsPrintf ("~"); 573 } 574 return (TRUE); 575 576 default: 577 break; 578 } 579 580 /* All other operators, emit an open paren */ 581 582 AcpiOsPrintf ("("); 583 return (TRUE); 584 } 585 586 587 /******************************************************************************* 588 * 589 * FUNCTION: AcpiDmIsOptimizationIgnored 590 * 591 * PARAMETERS: StoreOp - Store operator parse object 592 * StoreArgument - Target associate with the Op 593 * 594 * RETURN: TRUE if this Store operator should not be converted/removed. 595 * 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". 599 * 600 * Function is ignored if DoDisassemblerOptimizations is TRUE. 601 * This is the default, ignore this function. 602 * 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 607 * 608 * Store (Not (INT1), INT2) --> Not (INT1, INT2) 609 * --> INT2 = ~INT1 610 * 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) 616 * 617 ******************************************************************************/ 618 619 static BOOLEAN 620 AcpiDmIsOptimizationIgnored ( 621 ACPI_PARSE_OBJECT *StoreOp, 622 ACPI_PARSE_OBJECT *StoreArgument) 623 { 624 ACPI_PARSE_OBJECT *Argument1; 625 ACPI_PARSE_OBJECT *Argument2; 626 ACPI_PARSE_OBJECT *Target; 627 628 629 /* No optimizations/folding for the typical case */ 630 631 if (AcpiGbl_DoDisassemblerOptimizations) 632 { 633 return (FALSE); 634 } 635 636 /* 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. 641 */ 642 switch (StoreArgument->Common.AmlOpcode) 643 { 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: 654 655 /* These operators have two arguments and one target */ 656 657 Argument1 = StoreArgument->Common.Value.Arg; 658 Argument2 = Argument1->Common.Next; 659 Target = Argument2->Common.Next; 660 661 if (!AcpiDmIsValidTarget (Target)) 662 { 663 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 664 return (TRUE); 665 } 666 break; 667 668 case AML_DIVIDE_OP: 669 670 /* This operator has two arguments and two targets */ 671 672 Argument1 = StoreArgument->Common.Value.Arg; 673 Argument2 = Argument1->Common.Next; 674 Target = Argument2->Common.Next; 675 676 if (!AcpiDmIsValidTarget (Target) || 677 !AcpiDmIsValidTarget (Target->Common.Next)) 678 { 679 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 680 return (TRUE); 681 } 682 break; 683 684 case AML_BIT_NOT_OP: 685 686 /* This operator has one operand and one target */ 687 688 Argument1 = StoreArgument->Common.Value.Arg; 689 Target = Argument1->Common.Next; 690 691 if (!AcpiDmIsValidTarget (Target)) 692 { 693 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 694 return (TRUE); 695 } 696 break; 697 698 default: 699 break; 700 } 701 702 return (FALSE); 703 } 704 705 706 /******************************************************************************* 707 * 708 * FUNCTION: AcpiDmCloseOperator 709 * 710 * PARAMETERS: Op - Current parse object 711 * 712 * RETURN: None 713 * 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. 717 * 718 ******************************************************************************/ 719 720 void 721 AcpiDmCloseOperator ( 722 ACPI_PARSE_OBJECT *Op) 723 { 724 725 /* Always emit paren if ASL+ disassembly disabled */ 726 727 if (!AcpiGbl_CstyleDisassembly) 728 { 729 AcpiOsPrintf (")"); 730 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 731 return; 732 } 733 734 if (Op->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY) 735 { 736 AcpiOsPrintf (")"); 737 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 738 return; 739 } 740 741 /* Check if we need to add an additional closing paren */ 742 743 switch (Op->Common.AmlOpcode) 744 { 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: 760 761 /* Emit paren only if this is not a compound assignment */ 762 763 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT) 764 { 765 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 766 return; 767 } 768 769 /* Emit extra close paren for assignment within an expression */ 770 771 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT) 772 { 773 AcpiOsPrintf (")"); 774 } 775 break; 776 777 case AML_INDEX_OP: 778 779 /* This is case for unsupported Index() source constants */ 780 781 if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN) 782 { 783 AcpiOsPrintf (")"); 784 } 785 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 786 return; 787 788 /* No need for parens for these */ 789 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; 797 798 default: 799 800 /* Always emit paren for non-ASL+ operators */ 801 break; 802 } 803 804 AcpiOsPrintf (")"); 805 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 806 807 return; 808 } 809 810 811 /******************************************************************************* 812 * 813 * FUNCTION: AcpiDmGetCompoundSymbol 814 * 815 * PARAMETERS: AslOpcode 816 * 817 * RETURN: String containing the compound assignment symbol 818 * 819 * DESCRIPTION: Detect opcodes that can be converted to compound assignment, 820 * return the appropriate operator string. 821 * 822 ******************************************************************************/ 823 824 static char * 825 AcpiDmGetCompoundSymbol ( 826 UINT16 AmlOpcode) 827 { 828 char *Symbol; 829 830 831 switch (AmlOpcode) 832 { 833 case AML_ADD_OP: 834 Symbol = " += "; 835 break; 836 837 case AML_SUBTRACT_OP: 838 Symbol = " -= "; 839 break; 840 841 case AML_MULTIPLY_OP: 842 Symbol = " *= "; 843 break; 844 845 case AML_DIVIDE_OP: 846 Symbol = " /= "; 847 break; 848 849 case AML_MOD_OP: 850 Symbol = " %= "; 851 break; 852 853 case AML_SHIFT_LEFT_OP: 854 Symbol = " <<= "; 855 break; 856 857 case AML_SHIFT_RIGHT_OP: 858 Symbol = " >>= "; 859 break; 860 861 case AML_BIT_AND_OP: 862 Symbol = " &= "; 863 break; 864 865 case AML_BIT_OR_OP: 866 Symbol = " |= "; 867 break; 868 869 case AML_BIT_XOR_OP: 870 Symbol = " ^= "; 871 break; 872 873 default: 874 875 /* No operator string for all other opcodes */ 876 877 return (NULL); 878 } 879 880 return (Symbol); 881 } 882 883 884 /******************************************************************************* 885 * 886 * FUNCTION: AcpiDmPromoteTarget 887 * 888 * PARAMETERS: Op - Operator parse object 889 * Target - Target associate with the Op 890 * 891 * RETURN: None 892 * 893 * DESCRIPTION: Transform the parse tree by moving the target up to the first 894 * child of the Op. 895 * 896 ******************************************************************************/ 897 898 static void 899 AcpiDmPromoteTarget ( 900 ACPI_PARSE_OBJECT *Op, 901 ACPI_PARSE_OBJECT *Target) 902 { 903 ACPI_PARSE_OBJECT *Child; 904 905 906 /* Link target directly to the Op as first child */ 907 908 Child = Op->Common.Value.Arg; 909 Op->Common.Value.Arg = Target; 910 Target->Common.Next = Child; 911 912 /* Find the last peer, it is linked to the target. Unlink it. */ 913 914 while (Child->Common.Next != Target) 915 { 916 Child = Child->Common.Next; 917 } 918 919 Child->Common.Next = NULL; 920 } 921 922 923 /******************************************************************************* 924 * 925 * FUNCTION: AcpiDmIsValidTarget 926 * 927 * PARAMETERS: Target - Target Op from the parse tree 928 * 929 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder 930 * Op that was inserted by the parser. 931 * 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. 936 * 937 ******************************************************************************/ 938 939 static BOOLEAN 940 AcpiDmIsValidTarget ( 941 ACPI_PARSE_OBJECT *Target) 942 { 943 944 if (!Target) 945 { 946 return (FALSE); 947 } 948 949 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && 950 (Target->Common.Value.Arg == NULL)) 951 { 952 return (FALSE); 953 } 954 955 return (TRUE); 956 } 957 958 959 /******************************************************************************* 960 * 961 * FUNCTION: AcpiDmIsTargetAnOperand 962 * 963 * PARAMETERS: Target - Target associated with the expression 964 * Operand - An operand associated with expression 965 * 966 * RETURN: TRUE if expression can be converted to a compound assignment. 967 * FALSE otherwise. 968 * 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.) 972 * 973 ******************************************************************************/ 974 975 static BOOLEAN 976 AcpiDmIsTargetAnOperand ( 977 ACPI_PARSE_OBJECT *Target, 978 ACPI_PARSE_OBJECT *Operand, 979 BOOLEAN TopLevel) 980 { 981 const ACPI_OPCODE_INFO *OpInfo; 982 BOOLEAN Same; 983 984 985 /* 986 * Opcodes must match. Note: ignoring the difference between nameseg 987 * and namepath for now. May be needed later. 988 */ 989 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode) 990 { 991 return (FALSE); 992 } 993 994 /* Nodes should match, even if they are NULL */ 995 996 if (Target->Common.Node != Operand->Common.Node) 997 { 998 return (FALSE); 999 } 1000 1001 /* Determine if a child exists */ 1002 1003 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode); 1004 if (OpInfo->Flags & AML_HAS_ARGS) 1005 { 1006 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg, 1007 Operand->Common.Value.Arg, FALSE); 1008 if (!Same) 1009 { 1010 return (FALSE); 1011 } 1012 } 1013 1014 /* Check the next peer, as long as we are not at the top level */ 1015 1016 if ((!TopLevel) && 1017 Target->Common.Next) 1018 { 1019 Same = AcpiDmIsTargetAnOperand (Target->Common.Next, 1020 Operand->Common.Next, FALSE); 1021 if (!Same) 1022 { 1023 return (FALSE); 1024 } 1025 } 1026 1027 /* Supress the duplicate operand at the top-level */ 1028 1029 if (TopLevel) 1030 { 1031 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 1032 } 1033 return (TRUE); 1034 } 1035 1036 #endif 1037