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