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