xref: /freebsd/sys/contrib/dev/acpica/components/disassembler/dmcstyle.c (revision f126890ac5386406dadf7c4cfa9566cbb56537c5)
1 /*******************************************************************************
2  *
3  * Module Name: dmcstyle - Support for C-style operator disassembly
4  *
5  ******************************************************************************/
6 
7 /******************************************************************************
8  *
9  * 1. Copyright Notice
10  *
11  * Some or all of this work - Copyright (c) 1999 - 2023, Intel Corp.
12  * All rights reserved.
13  *
14  * 2. License
15  *
16  * 2.1. This is your license from Intel Corp. under its intellectual property
17  * rights. You may have additional license terms from the party that provided
18  * you this software, covering your right to use that party's intellectual
19  * property rights.
20  *
21  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
22  * copy of the source code appearing in this file ("Covered Code") an
23  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
24  * base code distributed originally by Intel ("Original Intel Code") to copy,
25  * make derivatives, distribute, use and display any portion of the Covered
26  * Code in any form, with the right to sublicense such rights; and
27  *
28  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
29  * license (with the right to sublicense), under only those claims of Intel
30  * patents that are infringed by the Original Intel Code, to make, use, sell,
31  * offer to sell, and import the Covered Code and derivative works thereof
32  * solely to the minimum extent necessary to exercise the above copyright
33  * license, and in no event shall the patent license extend to any additions
34  * to or modifications of the Original Intel Code. No other license or right
35  * is granted directly or by implication, estoppel or otherwise;
36  *
37  * The above copyright and patent license is granted only if the following
38  * conditions are met:
39  *
40  * 3. Conditions
41  *
42  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
43  * Redistribution of source code of any substantial portion of the Covered
44  * Code or modification with rights to further distribute source must include
45  * the above Copyright Notice, the above License, this list of Conditions,
46  * and the following Disclaimer and Export Compliance provision. In addition,
47  * Licensee must cause all Covered Code to which Licensee contributes to
48  * contain a file documenting the changes Licensee made to create that Covered
49  * Code and the date of any change. Licensee must include in that file the
50  * documentation of any changes made by any predecessor Licensee. Licensee
51  * must include a prominent statement that the modification is derived,
52  * directly or indirectly, from Original Intel Code.
53  *
54  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55  * Redistribution of source code of any substantial portion of the Covered
56  * Code or modification without rights to further distribute source must
57  * include the following Disclaimer and Export Compliance provision in the
58  * documentation and/or other materials provided with distribution. In
59  * addition, Licensee may not authorize further sublicense of source of any
60  * portion of the Covered Code, and must include terms to the effect that the
61  * license from Licensee to its licensee is limited to the intellectual
62  * property embodied in the software Licensee provides to its licensee, and
63  * not to intellectual property embodied in modifications its licensee may
64  * make.
65  *
66  * 3.3. Redistribution of Executable. Redistribution in executable form of any
67  * substantial portion of the Covered Code or modification must reproduce the
68  * above Copyright Notice, and the following Disclaimer and Export Compliance
69  * provision in the documentation and/or other materials provided with the
70  * distribution.
71  *
72  * 3.4. Intel retains all right, title, and interest in and to the Original
73  * Intel Code.
74  *
75  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
76  * Intel shall be used in advertising or otherwise to promote the sale, use or
77  * other dealings in products derived from or relating to the Covered Code
78  * without prior written authorization from Intel.
79  *
80  * 4. Disclaimer and Export Compliance
81  *
82  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83  * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
84  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
85  * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
86  * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
87  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
88  * PARTICULAR PURPOSE.
89  *
90  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
91  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
92  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
93  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
94  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
95  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
96  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
97  * LIMITED REMEDY.
98  *
99  * 4.3. Licensee shall not export, either directly or indirectly, any of this
100  * software or system incorporating such software without first obtaining any
101  * required license or other approval from the U. S. Department of Commerce or
102  * any other agency or department of the United States Government. In the
103  * event Licensee exports any such software from the United States or
104  * re-exports any such software from a foreign destination, Licensee shall
105  * ensure that the distribution and export/re-export of the software is in
106  * compliance with all laws, regulations, orders, or other restrictions of the
107  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
108  * any of its subsidiaries will export/re-export any technical data, process,
109  * software, or service, directly or indirectly, to any country for which the
110  * United States government or any agency thereof requires an export license,
111  * other governmental approval, or letter of assurance, without first obtaining
112  * such license, approval or letter.
113  *
114  *****************************************************************************
115  *
116  * Alternatively, you may choose to be licensed under the terms of the
117  * following license:
118  *
119  * Redistribution and use in source and binary forms, with or without
120  * modification, are permitted provided that the following conditions
121  * are met:
122  * 1. Redistributions of source code must retain the above copyright
123  *    notice, this list of conditions, and the following disclaimer,
124  *    without modification.
125  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
126  *    substantially similar to the "NO WARRANTY" disclaimer below
127  *    ("Disclaimer") and any redistribution must be conditioned upon
128  *    including a substantially similar Disclaimer requirement for further
129  *    binary redistribution.
130  * 3. Neither the names of the above-listed copyright holders nor the names
131  *    of any contributors may be used to endorse or promote products derived
132  *    from this software without specific prior written permission.
133  *
134  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
135  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
136  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
137  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
138  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
139  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
140  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
141  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
142  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
143  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
144  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
145  *
146  * Alternatively, you may choose to be licensed under the terms of the
147  * GNU General Public License ("GPL") version 2 as published by the Free
148  * Software Foundation.
149  *
150  *****************************************************************************/
151 
152 #include <contrib/dev/acpica/include/acpi.h>
153 #include <contrib/dev/acpica/include/accommon.h>
154 #include <contrib/dev/acpica/include/acparser.h>
155 #include <contrib/dev/acpica/include/amlcode.h>
156 #include <contrib/dev/acpica/include/acdebug.h>
157 #include <contrib/dev/acpica/include/acconvert.h>
158 
159 
160 #define _COMPONENT          ACPI_CA_DEBUGGER
161         ACPI_MODULE_NAME    ("dmcstyle")
162 
163 
164 /* Local prototypes */
165 
166 static char *
167 AcpiDmGetCompoundSymbol (
168    UINT16                   AslOpcode);
169 
170 static void
171 AcpiDmPromoteTarget (
172     ACPI_PARSE_OBJECT       *Op,
173     ACPI_PARSE_OBJECT       *Target);
174 
175 static BOOLEAN
176 AcpiDmIsValidTarget (
177     ACPI_PARSE_OBJECT       *Op);
178 
179 static BOOLEAN
180 AcpiDmIsTargetAnOperand (
181     ACPI_PARSE_OBJECT       *Target,
182     ACPI_PARSE_OBJECT       *Operand,
183     BOOLEAN                 TopLevel);
184 
185 static BOOLEAN
186 AcpiDmIsOptimizationIgnored (
187     ACPI_PARSE_OBJECT       *StoreOp,
188     ACPI_PARSE_OBJECT       *StoreArgument);
189 
190 
191 /*******************************************************************************
192  *
193  * FUNCTION:    AcpiDmCheckForSymbolicOpcode
194  *
195  * PARAMETERS:  Op                  - Current parse object
196  *              Walk                - Current parse tree walk info
197  *
198  * RETURN:      TRUE if opcode can be converted to symbolic, FALSE otherwise
199  *
200  * DESCRIPTION: This is the main code that implements disassembly of AML code
201  *              to C-style operators. Called during descending phase of the
202  *              parse tree walk.
203  *
204  ******************************************************************************/
205 
206 BOOLEAN
207 AcpiDmCheckForSymbolicOpcode (
208     ACPI_PARSE_OBJECT       *Op,
209     ACPI_OP_WALK_INFO       *Info)
210 {
211     char                    *OperatorSymbol = NULL;
212     ACPI_PARSE_OBJECT       *Argument1;
213     ACPI_PARSE_OBJECT       *Argument2;
214     ACPI_PARSE_OBJECT       *Target;
215     ACPI_PARSE_OBJECT       *Target2;
216 
217 
218     /* Exit immediately if ASL+ not enabled */
219 
220     if (!AcpiGbl_CstyleDisassembly)
221     {
222         return (FALSE);
223     }
224 
225     /* Get the first operand */
226 
227     Argument1 = AcpiPsGetArg (Op, 0);
228     if (!Argument1)
229     {
230         return (FALSE);
231     }
232 
233     /* Get the second operand */
234 
235     Argument2 = Argument1->Common.Next;
236 
237     /* Setup the operator string for this opcode */
238 
239     switch (Op->Common.AmlOpcode)
240     {
241     case AML_ADD_OP:
242         OperatorSymbol = " + ";
243         break;
244 
245     case AML_SUBTRACT_OP:
246         OperatorSymbol = " - ";
247         break;
248 
249     case AML_MULTIPLY_OP:
250         OperatorSymbol = " * ";
251         break;
252 
253     case AML_DIVIDE_OP:
254         OperatorSymbol = " / ";
255         break;
256 
257     case AML_MOD_OP:
258         OperatorSymbol = " % ";
259         break;
260 
261     case AML_SHIFT_LEFT_OP:
262         OperatorSymbol = " << ";
263         break;
264 
265     case AML_SHIFT_RIGHT_OP:
266         OperatorSymbol = " >> ";
267         break;
268 
269     case AML_BIT_AND_OP:
270         OperatorSymbol = " & ";
271         break;
272 
273     case AML_BIT_OR_OP:
274         OperatorSymbol = " | ";
275         break;
276 
277     case AML_BIT_XOR_OP:
278         OperatorSymbol = " ^ ";
279         break;
280 
281     /* Logical operators, no target */
282 
283     case AML_LOGICAL_AND_OP:
284         OperatorSymbol = " && ";
285         break;
286 
287     case AML_LOGICAL_EQUAL_OP:
288         OperatorSymbol = " == ";
289         break;
290 
291     case AML_LOGICAL_GREATER_OP:
292         OperatorSymbol = " > ";
293         break;
294 
295     case AML_LOGICAL_LESS_OP:
296         OperatorSymbol = " < ";
297         break;
298 
299     case AML_LOGICAL_OR_OP:
300         OperatorSymbol = " || ";
301         break;
302 
303     case AML_LOGICAL_NOT_OP:
304         /*
305          * Check for the LNOT sub-opcodes. These correspond to
306          * LNotEqual, LLessEqual, and LGreaterEqual. There are
307          * no actual AML opcodes for these operators.
308          */
309         switch (Argument1->Common.AmlOpcode)
310         {
311         case AML_LOGICAL_EQUAL_OP:
312             OperatorSymbol = " != ";
313             break;
314 
315         case AML_LOGICAL_GREATER_OP:
316             OperatorSymbol = " <= ";
317             break;
318 
319         case AML_LOGICAL_LESS_OP:
320             OperatorSymbol = " >= ";
321             break;
322 
323         default:
324 
325             /* Unary LNOT case, emit "!" immediately */
326 
327             AcpiOsPrintf ("!");
328             return (TRUE);
329         }
330 
331         Argument1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
332         Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
333 
334         /* Save symbol string in the next child (not peer) */
335 
336         Argument2 = AcpiPsGetArg (Argument1, 0);
337         if (!Argument2)
338         {
339             return (FALSE);
340         }
341 
342         Argument2->Common.OperatorSymbol = OperatorSymbol;
343         return (TRUE);
344 
345     case AML_INDEX_OP:
346         /*
347          * Check for constant source operand. Note: although technically
348          * legal syntax, the iASL compiler does not support this with
349          * the symbolic operators for Index(). It doesn't make sense to
350          * use Index() with a constant anyway.
351          */
352         if ((Argument1->Common.AmlOpcode == AML_STRING_OP)  ||
353             (Argument1->Common.AmlOpcode == AML_BUFFER_OP)  ||
354             (Argument1->Common.AmlOpcode == AML_PACKAGE_OP) ||
355             (Argument1->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP))
356         {
357             Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
358             return (FALSE);
359         }
360 
361         /* Index operator is [] */
362 
363         Argument1->Common.OperatorSymbol = " [";
364         Argument2->Common.OperatorSymbol = "]";
365         break;
366 
367     /* Unary operators */
368 
369     case AML_DECREMENT_OP:
370         OperatorSymbol = "--";
371         break;
372 
373     case AML_INCREMENT_OP:
374         OperatorSymbol = "++";
375         break;
376 
377     case AML_BIT_NOT_OP:
378     case AML_STORE_OP:
379         OperatorSymbol = NULL;
380         break;
381 
382     default:
383         return (FALSE);
384     }
385 
386     if (Argument1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
387     {
388         return (TRUE);
389     }
390 
391     /*
392      * This is the key to how the disassembly of the C-style operators
393      * works. We save the operator symbol in the first child, thus
394      * deferring symbol output until after the first operand has been
395      * emitted.
396      */
397     if (!Argument1->Common.OperatorSymbol)
398     {
399         Argument1->Common.OperatorSymbol = OperatorSymbol;
400     }
401 
402     /*
403      * Check for a valid target as the 3rd (or sometimes 2nd) operand
404      *
405      * Compound assignment operator support:
406      * Attempt to optimize constructs of the form:
407      *      Add (Local1, 0xFF, Local1)
408      * to:
409      *      Local1 += 0xFF
410      *
411      * Only the math operators and Store() have a target.
412      * Logicals have no target.
413      */
414     switch (Op->Common.AmlOpcode)
415     {
416     case AML_ADD_OP:
417     case AML_SUBTRACT_OP:
418     case AML_MULTIPLY_OP:
419     case AML_DIVIDE_OP:
420     case AML_MOD_OP:
421     case AML_SHIFT_LEFT_OP:
422     case AML_SHIFT_RIGHT_OP:
423     case AML_BIT_AND_OP:
424     case AML_BIT_OR_OP:
425     case AML_BIT_XOR_OP:
426 
427         /* Target is 3rd operand */
428 
429         Target = Argument2->Common.Next;
430         if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
431         {
432             Target2 = Target->Common.Next;
433 
434             /*
435              * Divide has an extra target operand (Remainder).
436              * Default behavior is to simply ignore ASL+ conversion
437              * if the remainder target (modulo) is specified.
438              */
439             if (!AcpiGbl_DoDisassemblerOptimizations)
440             {
441                 if (AcpiDmIsValidTarget (Target))
442                 {
443                     Argument1->Common.OperatorSymbol = NULL;
444                     Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
445                     return (FALSE);
446                 }
447 
448                 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
449                 Target = Target2;
450             }
451             else
452             {
453                 /*
454                  * Divide has an extra target operand (Remainder).
455                  * If both targets are specified, it cannot be converted
456                  * to a C-style operator.
457                  */
458                 if (AcpiDmIsValidTarget (Target) &&
459                     AcpiDmIsValidTarget (Target2))
460                 {
461                     Argument1->Common.OperatorSymbol = NULL;
462                     Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
463                     return (FALSE);
464                 }
465 
466                 if (AcpiDmIsValidTarget (Target)) /* Only first Target is valid (remainder) */
467                 {
468                     /* Convert the Divide to Modulo */
469 
470                     Op->Common.AmlOpcode = AML_MOD_OP;
471 
472                     Argument1->Common.OperatorSymbol = " % ";
473                     Target2->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
474                 }
475                 else /* Only second Target (quotient) is valid */
476                 {
477                     Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
478                     Target = Target2;
479                 }
480             }
481         }
482 
483         /* Parser should ensure there is at least a placeholder target */
484 
485         if (!Target)
486         {
487             return (FALSE);
488         }
489 
490         if (!AcpiDmIsValidTarget (Target))
491         {
492             /* Not a valid target (placeholder only, from parser) */
493             break;
494         }
495 
496         /*
497          * Promote the target up to the first child in the parse
498          * tree. This is done because the target will be output
499          * first, in the form:
500          *     <Target> = Operands...
501          */
502         AcpiDmPromoteTarget (Op, Target);
503 
504         /* Check operands for conversion to a "Compound Assignment" */
505 
506         switch (Op->Common.AmlOpcode)
507         {
508             /* Commutative operators */
509 
510         case AML_ADD_OP:
511         case AML_MULTIPLY_OP:
512         case AML_BIT_AND_OP:
513         case AML_BIT_OR_OP:
514         case AML_BIT_XOR_OP:
515             /*
516              * For the commutative operators, we can convert to a
517              * compound statement only if at least one (either) operand
518              * is the same as the target.
519              *
520              *      Add (A, B, A) --> A += B
521              *      Add (B, A, A) --> A += B
522              *      Add (B, C, A) --> A = (B + C)
523              */
524             if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)) ||
525                 (AcpiDmIsTargetAnOperand (Target, Argument2, TRUE)))
526             {
527                 Target->Common.OperatorSymbol =
528                     AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
529 
530                 /* Convert operator to compound assignment */
531 
532                 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
533                 Argument1->Common.OperatorSymbol = NULL;
534                 return (TRUE);
535             }
536             break;
537 
538             /* Non-commutative operators */
539 
540         case AML_SUBTRACT_OP:
541         case AML_DIVIDE_OP:
542         case AML_MOD_OP:
543         case AML_SHIFT_LEFT_OP:
544         case AML_SHIFT_RIGHT_OP:
545             /*
546              * For the non-commutative operators, we can convert to a
547              * compound statement only if the target is the same as the
548              * first operand.
549              *
550              *      Subtract (A, B, A) --> A -= B
551              *      Subtract (B, A, A) --> A = (B - A)
552              */
553             if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)))
554             {
555                 Target->Common.OperatorSymbol =
556                     AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
557 
558                 /* Convert operator to compound assignment */
559 
560                 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
561                 Argument1->Common.OperatorSymbol = NULL;
562                 return (TRUE);
563             }
564             break;
565 
566         default:
567             break;
568         }
569 
570         /*
571          * If we are within a C-style expression, emit an extra open
572          * paren. Implemented by examining the parent op.
573          */
574         switch (Op->Common.Parent->Common.AmlOpcode)
575         {
576         case AML_ADD_OP:
577         case AML_SUBTRACT_OP:
578         case AML_MULTIPLY_OP:
579         case AML_DIVIDE_OP:
580         case AML_MOD_OP:
581         case AML_SHIFT_LEFT_OP:
582         case AML_SHIFT_RIGHT_OP:
583         case AML_BIT_AND_OP:
584         case AML_BIT_OR_OP:
585         case AML_BIT_XOR_OP:
586         case AML_LOGICAL_AND_OP:
587         case AML_LOGICAL_EQUAL_OP:
588         case AML_LOGICAL_GREATER_OP:
589         case AML_LOGICAL_LESS_OP:
590         case AML_LOGICAL_OR_OP:
591 
592             Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
593             AcpiOsPrintf ("(");
594             break;
595 
596         default:
597             break;
598         }
599 
600         /* Normal output for ASL/AML operators with a target operand */
601 
602         Target->Common.OperatorSymbol = " = (";
603         return (TRUE);
604 
605     /* Binary operators, no parens */
606 
607     case AML_DECREMENT_OP:
608     case AML_INCREMENT_OP:
609         return (TRUE);
610 
611     case AML_INDEX_OP:
612 
613         /* Target is optional, 3rd operand */
614 
615         Target = Argument2->Common.Next;
616         if (AcpiDmIsValidTarget (Target))
617         {
618             AcpiDmPromoteTarget (Op, Target);
619 
620             if (!Target->Common.OperatorSymbol)
621             {
622                 Target->Common.OperatorSymbol = " = ";
623             }
624         }
625         return (TRUE);
626 
627     case AML_STORE_OP:
628         /*
629          * For Store, the Target is the 2nd operand. We know the target
630          * is valid, because it is not optional.
631          *
632          * Ignore any optimizations/folding if flag is set.
633          * Used for iASL/disassembler test suite only.
634          */
635         if (AcpiDmIsOptimizationIgnored (Op, Argument1))
636         {
637             return (FALSE);
638         }
639 
640         /*
641          * Perform conversion.
642          * In the parse tree, simply swap the target with the
643          * source so that the target is processed first.
644          */
645         Target = Argument1->Common.Next;
646         if (!Target)
647         {
648             return (FALSE);
649         }
650 
651         AcpiDmPromoteTarget (Op, Target);
652         if (!Target->Common.OperatorSymbol)
653         {
654             Target->Common.OperatorSymbol = " = ";
655         }
656         return (TRUE);
657 
658     case AML_BIT_NOT_OP:
659 
660         /* Target is optional, 2nd operand */
661 
662         Target = Argument1->Common.Next;
663         if (!Target)
664         {
665             return (FALSE);
666         }
667 
668         if (AcpiDmIsValidTarget (Target))
669         {
670             /* Valid target, not a placeholder */
671 
672             AcpiDmPromoteTarget (Op, Target);
673             Target->Common.OperatorSymbol = " = ~";
674         }
675         else
676         {
677             /* No target. Emit this prefix operator immediately */
678 
679             AcpiOsPrintf ("~");
680         }
681         return (TRUE);
682 
683     default:
684         break;
685     }
686 
687     /* All other operators, emit an open paren */
688 
689     AcpiOsPrintf ("(");
690     return (TRUE);
691 }
692 
693 
694 /*******************************************************************************
695  *
696  * FUNCTION:    AcpiDmIsOptimizationIgnored
697  *
698  * PARAMETERS:  StoreOp             - Store operator parse object
699  *              StoreArgument       - Target associate with the Op
700  *
701  * RETURN:      TRUE if this Store operator should not be converted/removed.
702  *
703  * DESCRIPTION: The following function implements "Do not optimize if a
704  *              store is immediately followed by a math/bit operator that
705  *              has no target".
706  *
707  *              Function is ignored if DoDisassemblerOptimizations is TRUE.
708  *              This is the default, ignore this function.
709  *
710  *              Disables these types of optimizations, and simply emits
711  *              legacy ASL code:
712  *                  Store (Add (INT1, 4), INT2) --> Add (INT1, 4, INT2)
713  *                                              --> INT2 = INT1 + 4
714  *
715  *                  Store (Not (INT1), INT2)    --> Not (INT1, INT2)
716  *                                              --> INT2 = ~INT1
717  *
718  *              Used only for the ASL test suite. For the test suite, we
719  *              don't want to perform some optimizations to ensure binary
720  *              compatibility with the generation of the legacy ASL->AML.
721  *              In other words, for all test modules we want exactly:
722  *                  (ASL+ -> AML) == (ASL- -> AML)
723  *
724  ******************************************************************************/
725 
726 static BOOLEAN
727 AcpiDmIsOptimizationIgnored (
728     ACPI_PARSE_OBJECT       *StoreOp,
729     ACPI_PARSE_OBJECT       *StoreArgument)
730 {
731     ACPI_PARSE_OBJECT       *Argument1;
732     ACPI_PARSE_OBJECT       *Argument2;
733     ACPI_PARSE_OBJECT       *Target;
734 
735 
736     /* No optimizations/folding for the typical case */
737 
738     if (AcpiGbl_DoDisassemblerOptimizations)
739     {
740         return (FALSE);
741     }
742 
743     /*
744      * Only a small subset of ASL/AML operators can be optimized.
745      * Can only optimize/fold if there is no target (or targets)
746      * specified for the operator. And of course, the operator
747      * is surrounded by a Store() operator.
748      */
749     switch (StoreArgument->Common.AmlOpcode)
750     {
751     case AML_ADD_OP:
752     case AML_SUBTRACT_OP:
753     case AML_MULTIPLY_OP:
754     case AML_MOD_OP:
755     case AML_SHIFT_LEFT_OP:
756     case AML_SHIFT_RIGHT_OP:
757     case AML_BIT_AND_OP:
758     case AML_BIT_OR_OP:
759     case AML_BIT_XOR_OP:
760     case AML_INDEX_OP:
761 
762         /* These operators have two arguments and one target */
763 
764         Argument1 = StoreArgument->Common.Value.Arg;
765         Argument2 = Argument1->Common.Next;
766         Target = Argument2->Common.Next;
767 
768         if (!AcpiDmIsValidTarget (Target))
769         {
770             StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
771             return (TRUE);
772         }
773         break;
774 
775     case AML_DIVIDE_OP:
776 
777         /* This operator has two arguments and two targets */
778 
779         Argument1 = StoreArgument->Common.Value.Arg;
780         Argument2 = Argument1->Common.Next;
781         Target = Argument2->Common.Next;
782 
783         if (!AcpiDmIsValidTarget (Target) ||
784             !AcpiDmIsValidTarget (Target->Common.Next))
785         {
786             StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
787             return (TRUE);
788         }
789         break;
790 
791     case AML_BIT_NOT_OP:
792 
793         /* This operator has one operand and one target */
794 
795         Argument1 = StoreArgument->Common.Value.Arg;
796         Target = Argument1->Common.Next;
797 
798         if (!AcpiDmIsValidTarget (Target))
799         {
800             StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
801             return (TRUE);
802         }
803         break;
804 
805     default:
806         break;
807     }
808 
809     return (FALSE);
810 }
811 
812 
813 /*******************************************************************************
814  *
815  * FUNCTION:    AcpiDmCloseOperator
816  *
817  * PARAMETERS:  Op                  - Current parse object
818  *
819  * RETURN:      None
820  *
821  * DESCRIPTION: Closes an operator by adding a closing parentheses if and
822  *              when necessary. Called during ascending phase of the
823  *              parse tree walk.
824  *
825  ******************************************************************************/
826 
827 void
828 AcpiDmCloseOperator (
829     ACPI_PARSE_OBJECT       *Op)
830 {
831 
832     /* Always emit paren if ASL+ disassembly disabled */
833 
834     if (!AcpiGbl_CstyleDisassembly)
835     {
836         AcpiOsPrintf (")");
837         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
838         return;
839     }
840 
841     if (Op->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY)
842     {
843         AcpiOsPrintf (")");
844         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
845         return;
846     }
847 
848     /* Check if we need to add an additional closing paren */
849 
850     switch (Op->Common.AmlOpcode)
851     {
852     case AML_ADD_OP:
853     case AML_SUBTRACT_OP:
854     case AML_MULTIPLY_OP:
855     case AML_DIVIDE_OP:
856     case AML_MOD_OP:
857     case AML_SHIFT_LEFT_OP:
858     case AML_SHIFT_RIGHT_OP:
859     case AML_BIT_AND_OP:
860     case AML_BIT_OR_OP:
861     case AML_BIT_XOR_OP:
862     case AML_LOGICAL_AND_OP:
863     case AML_LOGICAL_EQUAL_OP:
864     case AML_LOGICAL_GREATER_OP:
865     case AML_LOGICAL_LESS_OP:
866     case AML_LOGICAL_OR_OP:
867 
868         /* Emit paren only if this is not a compound assignment */
869 
870         if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT)
871         {
872             ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
873             return;
874         }
875 
876         /* Emit extra close paren for assignment within an expression */
877 
878         if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
879         {
880             AcpiOsPrintf (")");
881         }
882         break;
883 
884     case AML_INDEX_OP:
885 
886         /* This is case for unsupported Index() source constants */
887 
888         if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
889         {
890             AcpiOsPrintf (")");
891         }
892         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
893         return;
894 
895     /* No need for parens for these */
896 
897     case AML_DECREMENT_OP:
898     case AML_INCREMENT_OP:
899     case AML_LOGICAL_NOT_OP:
900     case AML_BIT_NOT_OP:
901     case AML_STORE_OP:
902         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
903         return;
904 
905     default:
906 
907         /* Always emit paren for non-ASL+ operators */
908         break;
909     }
910 
911     AcpiOsPrintf (")");
912     ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
913 
914     return;
915 }
916 
917 
918 /*******************************************************************************
919  *
920  * FUNCTION:    AcpiDmGetCompoundSymbol
921  *
922  * PARAMETERS:  AslOpcode
923  *
924  * RETURN:      String containing the compound assignment symbol
925  *
926  * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
927  *              return the appropriate operator string.
928  *
929  ******************************************************************************/
930 
931 static char *
932 AcpiDmGetCompoundSymbol (
933    UINT16                   AmlOpcode)
934 {
935     char                    *Symbol;
936 
937 
938     switch (AmlOpcode)
939     {
940     case AML_ADD_OP:
941         Symbol = " += ";
942         break;
943 
944     case AML_SUBTRACT_OP:
945         Symbol = " -= ";
946         break;
947 
948     case AML_MULTIPLY_OP:
949         Symbol = " *= ";
950         break;
951 
952     case AML_DIVIDE_OP:
953         Symbol = " /= ";
954         break;
955 
956     case AML_MOD_OP:
957         Symbol = " %= ";
958         break;
959 
960     case AML_SHIFT_LEFT_OP:
961         Symbol = " <<= ";
962         break;
963 
964     case AML_SHIFT_RIGHT_OP:
965         Symbol = " >>= ";
966         break;
967 
968     case AML_BIT_AND_OP:
969         Symbol = " &= ";
970         break;
971 
972     case AML_BIT_OR_OP:
973         Symbol = " |= ";
974         break;
975 
976     case AML_BIT_XOR_OP:
977         Symbol = " ^= ";
978         break;
979 
980     default:
981 
982         /* No operator string for all other opcodes */
983 
984         return (NULL);
985     }
986 
987     return (Symbol);
988 }
989 
990 
991 /*******************************************************************************
992  *
993  * FUNCTION:    AcpiDmPromoteTarget
994  *
995  * PARAMETERS:  Op                  - Operator parse object
996  *              Target              - Target associate with the Op
997  *
998  * RETURN:      None
999  *
1000  * DESCRIPTION: Transform the parse tree by moving the target up to the first
1001  *              child of the Op.
1002  *
1003  ******************************************************************************/
1004 
1005 static void
1006 AcpiDmPromoteTarget (
1007     ACPI_PARSE_OBJECT       *Op,
1008     ACPI_PARSE_OBJECT       *Target)
1009 {
1010     ACPI_PARSE_OBJECT       *Child;
1011 
1012 
1013     /* Link target directly to the Op as first child */
1014 
1015     Child = Op->Common.Value.Arg;
1016     Op->Common.Value.Arg = Target;
1017     Target->Common.Next = Child;
1018 
1019     /* Find the last peer, it is linked to the target. Unlink it. */
1020 
1021     while (Child->Common.Next != Target)
1022     {
1023         Child = Child->Common.Next;
1024     }
1025 
1026     Child->Common.Next = NULL;
1027 }
1028 
1029 
1030 /*******************************************************************************
1031  *
1032  * FUNCTION:    AcpiDmIsValidTarget
1033  *
1034  * PARAMETERS:  Target              - Target Op from the parse tree
1035  *
1036  * RETURN:      TRUE if the Target is real. FALSE if it is just a placeholder
1037  *              Op that was inserted by the parser.
1038  *
1039  * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
1040  *              In other words, determine if the optional target is used or
1041  *              not. Note: If Target is NULL, something is seriously wrong,
1042  *              probably with the parse tree.
1043  *
1044  ******************************************************************************/
1045 
1046 static BOOLEAN
1047 AcpiDmIsValidTarget (
1048     ACPI_PARSE_OBJECT       *Target)
1049 {
1050 
1051     if (!Target)
1052     {
1053         return (FALSE);
1054     }
1055 
1056     if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
1057         (Target->Common.Value.Arg == NULL))
1058     {
1059         return (FALSE);
1060     }
1061 
1062     return (TRUE);
1063 }
1064 
1065 
1066 /*******************************************************************************
1067  *
1068  * FUNCTION:    AcpiDmIsTargetAnOperand
1069  *
1070  * PARAMETERS:  Target              - Target associated with the expression
1071  *              Operand             - An operand associated with expression
1072  *
1073  * RETURN:      TRUE if expression can be converted to a compound assignment.
1074  *              FALSE otherwise.
1075  *
1076  * DESCRIPTION: Determine if the Target duplicates the operand, in order to
1077  *              detect if the expression can be converted to a compound
1078  *              assignment. (+=, *=, etc.)
1079  *
1080  ******************************************************************************/
1081 
1082 static BOOLEAN
1083 AcpiDmIsTargetAnOperand (
1084     ACPI_PARSE_OBJECT       *Target,
1085     ACPI_PARSE_OBJECT       *Operand,
1086     BOOLEAN                 TopLevel)
1087 {
1088     const ACPI_OPCODE_INFO  *OpInfo;
1089     BOOLEAN                 Same;
1090 
1091 
1092     /*
1093      * Opcodes must match. Note: ignoring the difference between nameseg
1094      * and namepath for now. May be needed later.
1095      */
1096     if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
1097     {
1098         return (FALSE);
1099     }
1100 
1101     /* Nodes should match, even if they are NULL */
1102 
1103     if (Target->Common.Node != Operand->Common.Node)
1104     {
1105         return (FALSE);
1106     }
1107 
1108     /* Determine if a child exists */
1109 
1110     OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
1111     if (OpInfo->Flags & AML_HAS_ARGS)
1112     {
1113         Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
1114             Operand->Common.Value.Arg, FALSE);
1115         if (!Same)
1116         {
1117             return (FALSE);
1118         }
1119     }
1120 
1121     /* Check the next peer, as long as we are not at the top level */
1122 
1123     if ((!TopLevel) &&
1124          Target->Common.Next)
1125     {
1126         Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
1127             Operand->Common.Next, FALSE);
1128         if (!Same)
1129         {
1130             return (FALSE);
1131         }
1132     }
1133 
1134     /* Suppress the duplicate operand at the top-level */
1135 
1136     if (TopLevel)
1137     {
1138         Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1139     }
1140     return (TRUE);
1141 }
1142