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