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