xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/aslfold.c (revision 046a29855e04359424fd074e8313af6b6be8cfb6)
1 /******************************************************************************
2  *
3  * Module Name: aslfold - Constant folding
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2023, 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 MERCHANTABILITY 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 "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "amlcode.h"
47 
48 #include "acdispat.h"
49 #include "acparser.h"
50 
51 #define _COMPONENT          ACPI_COMPILER
52         ACPI_MODULE_NAME    ("aslfold")
53 
54 /* Local prototypes */
55 
56 static ACPI_STATUS
57 OpcAmlEvaluationWalk1 (
58     ACPI_PARSE_OBJECT       *Op,
59     UINT32                  Level,
60     void                    *Context);
61 
62 static ACPI_STATUS
63 OpcAmlEvaluationWalk2 (
64     ACPI_PARSE_OBJECT       *Op,
65     UINT32                  Level,
66     void                    *Context);
67 
68 static ACPI_STATUS
69 OpcAmlCheckForConstant (
70     ACPI_PARSE_OBJECT       *Op,
71     UINT32                  Level,
72     void                    *Context);
73 
74 static void
75 OpcUpdateIntegerNode (
76     ACPI_PARSE_OBJECT       *Op,
77     UINT64                  Value);
78 
79 static ACPI_STATUS
80 TrTransformToStoreOp (
81     ACPI_PARSE_OBJECT       *Op,
82     ACPI_WALK_STATE         *WalkState);
83 
84 static ACPI_STATUS
85 TrSimpleConstantReduction (
86     ACPI_PARSE_OBJECT       *Op,
87     ACPI_WALK_STATE         *WalkState);
88 
89 static void
90 TrInstallReducedConstant (
91     ACPI_PARSE_OBJECT       *Op,
92     ACPI_OPERAND_OBJECT     *ObjDesc);
93 
94 
95 /*******************************************************************************
96  *
97  * FUNCTION:    OpcAmlConstantWalk
98  *
99  * PARAMETERS:  ASL_WALK_CALLBACK
100  *
101  * RETURN:      Status
102  *
103  * DESCRIPTION: Reduce an Op and its subtree to a constant if possible.
104  *              Called during ascent of the parse tree.
105  *
106  ******************************************************************************/
107 
108 ACPI_STATUS
OpcAmlConstantWalk(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)109 OpcAmlConstantWalk (
110     ACPI_PARSE_OBJECT       *Op,
111     UINT32                  Level,
112     void                    *Context)
113 {
114     ACPI_WALK_STATE         *WalkState;
115     ACPI_STATUS             Status = AE_OK;
116 
117 
118     if (Op->Asl.CompileFlags == 0)
119     {
120         return (AE_OK);
121     }
122 
123     /*
124      * Only interested in subtrees that could possibly contain
125      * expressions that can be evaluated at this time
126      */
127     if ((!(Op->Asl.CompileFlags & OP_COMPILE_TIME_CONST)) ||
128           (Op->Asl.CompileFlags & OP_IS_TARGET))
129     {
130         return (AE_OK);
131     }
132 
133     /* Create a new walk state */
134 
135     WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
136     if (!WalkState)
137     {
138         return (AE_NO_MEMORY);
139     }
140 
141     WalkState->NextOp = NULL;
142     WalkState->Params = NULL;
143 
144     /*
145      * Examine the entire subtree -- all nodes must be constants
146      * or type 3/4/5 opcodes
147      */
148     Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
149         OpcAmlCheckForConstant, NULL, WalkState);
150 
151     /*
152      * Did we find an entire subtree that contains all constants
153      * and type 3/4/5 opcodes?
154      */
155     switch (Status)
156     {
157     case AE_OK:
158 
159         /* Simple case, like Add(3,4) -> 7 */
160 
161         Status = TrSimpleConstantReduction (Op, WalkState);
162         break;
163 
164     case AE_CTRL_RETURN_VALUE:
165 
166         /* More complex case, like Add(3,4,Local0) -> Store(7,Local0) */
167 
168         Status = TrTransformToStoreOp (Op, WalkState);
169         break;
170 
171     case AE_TYPE:
172 
173         AcpiDsDeleteWalkState (WalkState);
174         return (AE_OK);
175 
176     default:
177         AcpiDsDeleteWalkState (WalkState);
178         break;
179     }
180 
181     if (ACPI_FAILURE (Status))
182     {
183         DbgPrint (ASL_PARSE_OUTPUT, "Cannot resolve, %s\n",
184             AcpiFormatException (Status));
185 
186         /* We could not resolve the subtree for some reason */
187 
188         AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
189             (char *) AcpiFormatException (Status));
190 
191         /* Set the subtree value to ZERO anyway. Eliminates further errors */
192 
193         OpcUpdateIntegerNode (Op, 0);
194     }
195 
196     return (AE_OK);
197 }
198 
199 
200 /*******************************************************************************
201  *
202  * FUNCTION:    OpcAmlCheckForConstant
203  *
204  * PARAMETERS:  ASL_WALK_CALLBACK
205  *
206  * RETURN:      Status
207  *
208  * DESCRIPTION: Check one Op for a reducible type 3/4/5 AML opcode.
209  *              This is performed via an upward walk of the parse subtree.
210  *
211  ******************************************************************************/
212 
213 static ACPI_STATUS
OpcAmlCheckForConstant(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)214 OpcAmlCheckForConstant (
215     ACPI_PARSE_OBJECT       *Op,
216     UINT32                  Level,
217     void                    *Context)
218 {
219     ACPI_WALK_STATE         *WalkState = Context;
220     ACPI_STATUS             Status = AE_OK;
221     ACPI_PARSE_OBJECT       *NextOp;
222     const ACPI_OPCODE_INFO  *OpInfo;
223 
224 
225     WalkState->Op = Op;
226     WalkState->Opcode = Op->Common.AmlOpcode;
227     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
228 
229     DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ",
230         Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
231 
232     /*
233      * These opcodes do not appear in the OpcodeInfo table, but
234      * they represent constants, so abort the constant walk now.
235      */
236     if ((WalkState->Opcode == AML_RAW_DATA_BYTE) ||
237         (WalkState->Opcode == AML_RAW_DATA_WORD) ||
238         (WalkState->Opcode == AML_RAW_DATA_DWORD) ||
239         (WalkState->Opcode == AML_RAW_DATA_QWORD))
240     {
241         DbgPrint (ASL_PARSE_OUTPUT, "RAW DATA");
242         Status = AE_TYPE;
243         goto CleanupAndExit;
244     }
245 
246     /*
247      * Search upwards for a possible Name() operator. This is done
248      * because a type 3/4/5 opcode within a Name() expression
249      * MUST be reduced to a simple constant.
250      */
251     NextOp = Op->Asl.Parent;
252     while (NextOp)
253     {
254         /* Finished if we find a Name() opcode */
255 
256         if (NextOp->Asl.AmlOpcode == AML_NAME_OP)
257         {
258             break;
259         }
260 
261         /*
262          * Any "deferred" opcodes contain one or more TermArg parameters,
263          * and thus are not required to be folded to constants at compile
264          * time. This affects things like Buffer() and Package() objects.
265          * We just ignore them here. However, any sub-expressions can and
266          * will still be typechecked. Note: These are called the
267          * "deferred" opcodes in the AML interpreter.
268          */
269         OpInfo = AcpiPsGetOpcodeInfo (NextOp->Common.AmlOpcode);
270         if (OpInfo->Flags & AML_DEFER)
271         {
272             NextOp = NULL;
273             break;
274         }
275 
276         NextOp = NextOp->Asl.Parent;
277     }
278 
279     /* Type 3/4/5 opcodes have the AML_CONSTANT flag set */
280 
281     if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
282     {
283         /*
284          * From the ACPI specification:
285          *
286          * "The Type 3/4/5 opcodes return a value and can be used in an
287          * expression that evaluates to a constant. These opcodes may be
288          * evaluated at ASL compile-time. To ensure that these opcodes
289          * will evaluate to a constant, the following rules apply: The
290          * term cannot have a destination (target) operand, and must have
291          * either a Type3Opcode, Type4Opcode, Type5Opcode, ConstExprTerm,
292          * Integer, BufferTerm, Package, or String for all arguments."
293          */
294 
295         /*
296          * The value (second) operand for the Name() operator MUST
297          * reduce to a single constant, as per the ACPI specification
298          * (the operand is a DataObject). This also implies that there
299          * can be no target operand. Name() is the only ASL operator
300          * with a "DataObject" as an operand and is thus special-
301          * cased here.
302          */
303         if (NextOp) /* Inspect a Name() operator */
304         {
305             /* Error if there is a target operand */
306 
307             if (Op->Asl.CompileFlags & OP_IS_TARGET)
308             {
309                 AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op, NULL);
310                 Status = AE_TYPE;
311             }
312 
313             /* Error if expression cannot be reduced (folded) */
314 
315             if (!(NextOp->Asl.CompileFlags & OP_COULD_NOT_REDUCE))
316             {
317                 /* Ensure only one error message per statement */
318 
319                 NextOp->Asl.CompileFlags |= OP_COULD_NOT_REDUCE;
320                 DbgPrint (ASL_PARSE_OUTPUT,
321                     "**** Could not reduce operands for NAME opcode ****\n");
322 
323                 AslError (ASL_ERROR, ASL_MSG_CONSTANT_REQUIRED, Op,
324                     "Constant is required for Name operator");
325                 Status = AE_TYPE;
326             }
327         }
328 
329         if (ACPI_FAILURE (Status))
330         {
331             goto CleanupAndExit;
332         }
333 
334         /* This is not a 3/4/5 opcode, but maybe can convert to STORE */
335 
336         if (Op->Asl.CompileFlags & OP_IS_TARGET)
337         {
338             DbgPrint (ASL_PARSE_OUTPUT,
339                 "**** Valid Target, transform to Store or CopyObject ****\n");
340             return (AE_CTRL_RETURN_VALUE);
341         }
342 
343         /* Expression cannot be reduced */
344 
345         DbgPrint (ASL_PARSE_OUTPUT,
346             "**** Not a Type 3/4/5 opcode or cannot reduce/fold (%s) ****\n",
347              Op->Asl.ParseOpName);
348 
349         Status = AE_TYPE;
350         goto CleanupAndExit;
351     }
352 
353     /*
354      * TBD: Ignore buffer constants for now. The problem is that these
355      * constants have been transformed into RAW_DATA at this point, from
356      * the parse tree transform process which currently happens before
357      * the constant folding process. We may need to defer this transform
358      * for buffer until after the constant folding.
359      */
360     if (WalkState->Opcode == AML_BUFFER_OP)
361     {
362         DbgPrint (ASL_PARSE_OUTPUT,
363             "\nBuffer constant reduction is currently not supported\n");
364 
365         if (NextOp) /* Found a Name() operator, error */
366         {
367             AslError (ASL_ERROR, ASL_MSG_UNSUPPORTED, Op,
368                 "Buffer expression cannot be reduced");
369         }
370 
371         Status = AE_TYPE;
372         goto CleanupAndExit;
373     }
374 
375     /* Debug output */
376 
377     DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345");
378 
379     if (Op->Asl.CompileFlags & OP_IS_TARGET)
380     {
381         if (Op->Asl.ParseOpcode == PARSEOP_ZERO)
382         {
383             DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " NULL TARGET");
384         }
385         else
386         {
387             DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " VALID TARGET");
388         }
389     }
390 
391     if (Op->Asl.CompileFlags & OP_IS_TERM_ARG)
392     {
393         DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " TERMARG");
394     }
395 
396 CleanupAndExit:
397 
398     /* Dump the node compile flags also */
399 
400     TrPrintOpFlags (Op->Asl.CompileFlags, ASL_PARSE_OUTPUT);
401     DbgPrint (ASL_PARSE_OUTPUT, "\n");
402     return (Status);
403 }
404 
405 
406 /*******************************************************************************
407  *
408  * FUNCTION:    TrSimpleConstantReduction
409  *
410  * PARAMETERS:  Op                  - Parent operator to be transformed
411  *              WalkState           - Current walk state
412  *
413  * RETURN:      Status
414  *
415  * DESCRIPTION: Reduce an entire AML operation to a single constant. The
416  *              operation must not have a target operand.
417  *
418  *              Add (32,64) --> 96
419  *
420  ******************************************************************************/
421 
422 static ACPI_STATUS
TrSimpleConstantReduction(ACPI_PARSE_OBJECT * Op,ACPI_WALK_STATE * WalkState)423 TrSimpleConstantReduction (
424     ACPI_PARSE_OBJECT       *Op,
425     ACPI_WALK_STATE         *WalkState)
426 {
427     ACPI_PARSE_OBJECT       *RootOp;
428     ACPI_PARSE_OBJECT       *OriginalParentOp;
429     ACPI_OPERAND_OBJECT     *ObjDesc;
430     ACPI_STATUS             Status;
431 
432 
433     DbgPrint (ASL_PARSE_OUTPUT,
434         "Simple subtree constant reduction, operator to constant\n");
435 
436     /* Allocate a new temporary root for this subtree */
437 
438     RootOp = TrAllocateOp (PARSEOP_INTEGER);
439     if (!RootOp)
440     {
441         return (AE_NO_MEMORY);
442     }
443 
444     RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
445 
446     OriginalParentOp = Op->Common.Parent;
447     Op->Common.Parent = RootOp;
448 
449     /* Hand off the subtree to the AML interpreter */
450 
451     WalkState->CallerReturnDesc = &ObjDesc;
452 
453     Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
454         OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
455 
456     /* Restore original parse tree */
457 
458     Op->Common.Parent = OriginalParentOp;
459 
460     if (ACPI_FAILURE (Status))
461     {
462         DbgPrint (ASL_PARSE_OUTPUT,
463             "Constant Subtree evaluation(1), %s\n",
464             AcpiFormatException (Status));
465         return (Status);
466     }
467 
468     /* Get the final result */
469 
470     Status = AcpiDsResultPop (&ObjDesc, WalkState);
471     if (ACPI_FAILURE (Status))
472     {
473         DbgPrint (ASL_PARSE_OUTPUT,
474             "Constant Subtree evaluation(2), %s\n",
475             AcpiFormatException (Status));
476         return (Status);
477     }
478 
479     /* Disconnect any existing children, install new constant */
480 
481     Op->Asl.Child = NULL;
482     TrInstallReducedConstant (Op, ObjDesc);
483 
484     UtSetParseOpName (Op);
485     return (AE_OK);
486 }
487 
488 
489 /*******************************************************************************
490  *
491  * FUNCTION:    TrTransformToStoreOp
492  *
493  * PARAMETERS:  Op                  - Parent operator to be transformed
494  *              WalkState           - Current walk state
495  *
496  * RETURN:      Status
497  *
498  * DESCRIPTION: Transforms a single AML operation with a constant and target
499  *              to a simple store operation:
500  *
501  *              Add (32,64,DATA) --> Store (96,DATA)
502  *
503  ******************************************************************************/
504 
505 static ACPI_STATUS
TrTransformToStoreOp(ACPI_PARSE_OBJECT * Op,ACPI_WALK_STATE * WalkState)506 TrTransformToStoreOp (
507     ACPI_PARSE_OBJECT       *Op,
508     ACPI_WALK_STATE         *WalkState)
509 {
510     ACPI_PARSE_OBJECT       *OriginalTarget;
511     ACPI_PARSE_OBJECT       *NewTarget;
512     ACPI_PARSE_OBJECT       *Child1;
513     ACPI_PARSE_OBJECT       *Child2;
514     ACPI_OPERAND_OBJECT     *ObjDesc;
515     ACPI_PARSE_OBJECT       *NewParent;
516     ACPI_PARSE_OBJECT       *OriginalParent;
517     ACPI_STATUS             Status;
518     UINT16                  NewParseOpcode;
519     UINT16                  NewAmlOpcode;
520 
521 
522     /* Extract the operands */
523 
524     Child1 = Op->Asl.Child;
525     Child2 = Child1->Asl.Next;
526 
527     /*
528      * Special case for DIVIDE -- it has two targets. The first
529      * is for the remainder and if present, we will not attempt
530      * to reduce the expression.
531      */
532     if (Op->Asl.ParseOpcode == PARSEOP_DIVIDE)
533     {
534         Child2 = Child2->Asl.Next;
535         if (Child2->Asl.ParseOpcode != PARSEOP_ZERO)
536         {
537             DbgPrint (ASL_PARSE_OUTPUT,
538                 "Cannot reduce DIVIDE - has two targets\n\n");
539             return (AE_OK);
540         }
541     }
542 
543     switch (Op->Asl.ParseOpcode)
544     {
545     /*
546      * Folding of the explicit conversion opcodes must use CopyObject
547      * instead of Store. This can change the object type of the target
548      * operand, as per the ACPI specification:
549      *
550      * "If the ASL operator is one of the explicit conversion operators
551      * (ToString, ToInteger, etc., and the CopyObject operator), no
552      * [implicit] conversion is performed. (In other words, the result
553      * object is stored directly to the target and completely overwrites
554      * any existing object already stored at the target)"
555      */
556     case PARSEOP_TOINTEGER:
557     case PARSEOP_TOSTRING:
558     case PARSEOP_TOBUFFER:
559     case PARSEOP_TODECIMALSTRING:
560     case PARSEOP_TOHEXSTRING:
561     case PARSEOP_TOBCD:
562     case PARSEOP_FROMBCD:
563 
564         NewParseOpcode = PARSEOP_COPYOBJECT;
565         NewAmlOpcode = AML_COPY_OBJECT_OP;
566 
567         DbgPrint (ASL_PARSE_OUTPUT,
568             "Reduction/Transform to CopyObjectOp: CopyObject(%s, %s)\n",
569             Child1->Asl.ParseOpName, Child2->Asl.ParseOpName);
570         break;
571 
572     default:
573 
574         NewParseOpcode = PARSEOP_STORE;
575         NewAmlOpcode = AML_STORE_OP;
576 
577         DbgPrint (ASL_PARSE_OUTPUT,
578             "Reduction/Transform to StoreOp: Store(%s, %s)\n",
579             Child1->Asl.ParseOpName, Child2->Asl.ParseOpName);
580         break;
581     }
582 
583     /*
584      * Create a NULL (zero) target so that we can use the
585      * interpreter to evaluate the expression.
586      */
587     NewTarget = TrCreateNullTargetOp ();
588     NewTarget->Common.AmlOpcode = AML_INT_NAMEPATH_OP;
589 
590     /* Handle one-operand cases (NOT, TOBCD, etc.) */
591 
592     if (!Child2->Asl.Next)
593     {
594         Child2 = Child1;
595     }
596 
597     /* Link in new NULL target as the last operand */
598 
599     OriginalTarget = Child2->Asl.Next;
600     Child2->Asl.Next = NewTarget;
601     NewTarget->Asl.Parent = OriginalTarget->Asl.Parent;
602 
603     NewParent = TrAllocateOp (PARSEOP_INTEGER);
604     NewParent->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
605 
606     OriginalParent = Op->Common.Parent;
607     Op->Common.Parent = NewParent;
608 
609     /* Hand off the subtree to the AML interpreter */
610 
611     WalkState->CallerReturnDesc = &ObjDesc;
612 
613     Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
614         OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
615     if (ACPI_FAILURE (Status))
616     {
617         DbgPrint (ASL_PARSE_OUTPUT,
618             "Constant Subtree evaluation(3), %s\n",
619             AcpiFormatException (Status));
620         goto EvalError;
621     }
622 
623     /* Get the final result */
624 
625     Status = AcpiDsResultPop (&ObjDesc, WalkState);
626     if (ACPI_FAILURE (Status))
627     {
628         DbgPrint (ASL_PARSE_OUTPUT,
629             "Constant Subtree evaluation(4), %s\n",
630             AcpiFormatException (Status));
631         goto EvalError;
632     }
633 
634     /* Truncate any subtree expressions, they have been evaluated */
635 
636     Child1->Asl.Child = NULL;
637 
638     /* Folded constant is in ObjDesc, store into Child1 */
639 
640     TrInstallReducedConstant (Child1, ObjDesc);
641 
642     /* Convert operator to STORE or COPYOBJECT */
643 
644     Op->Asl.ParseOpcode = NewParseOpcode;
645     Op->Asl.AmlOpcode = NewAmlOpcode;
646     UtSetParseOpName (Op);
647     Op->Common.Parent = OriginalParent;
648 
649     /* First child is the folded constant */
650 
651     /* Second child will be the target */
652 
653     Child1->Asl.Next = OriginalTarget;
654     return (AE_OK);
655 
656 
657 EvalError:
658 
659     /* Restore original links */
660 
661     Op->Common.Parent = OriginalParent;
662     Child2->Asl.Next = OriginalTarget;
663     return (Status);
664 }
665 
666 
667 /*******************************************************************************
668  *
669  * FUNCTION:    TrInstallReducedConstant
670  *
671  * PARAMETERS:  Op                  - Parent operator to be transformed
672  *              ObjDesc             - Reduced constant to be installed
673  *
674  * RETURN:      None
675  *
676  * DESCRIPTION: Transform the original operator to a simple constant.
677  *              Handles Integers, Strings, and Buffers.
678  *
679  ******************************************************************************/
680 
681 static void
TrInstallReducedConstant(ACPI_PARSE_OBJECT * Op,ACPI_OPERAND_OBJECT * ObjDesc)682 TrInstallReducedConstant (
683     ACPI_PARSE_OBJECT       *Op,
684     ACPI_OPERAND_OBJECT     *ObjDesc)
685 {
686     ACPI_PARSE_OBJECT       *LengthOp;
687     ACPI_PARSE_OBJECT       *DataOp;
688 
689 
690     AslGbl_TotalFolds++;
691     AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
692         Op->Asl.ParseOpName);
693 
694     /*
695      * Because we know we executed type 3/4/5 opcodes above, we know that
696      * the result must be either an Integer, String, or Buffer.
697      */
698     switch (ObjDesc->Common.Type)
699     {
700     case ACPI_TYPE_INTEGER:
701 
702         OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value);
703 
704         DbgPrint (ASL_PARSE_OUTPUT,
705             "Constant expression reduced to (%s) %8.8X%8.8X\n\n",
706             Op->Asl.ParseOpName,
707             ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
708         break;
709 
710     case ACPI_TYPE_STRING:
711 
712         Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
713         Op->Common.AmlOpcode = AML_STRING_OP;
714         Op->Asl.AmlLength = strlen (ObjDesc->String.Pointer) + 1;
715         Op->Common.Value.String = ObjDesc->String.Pointer;
716 
717         DbgPrint (ASL_PARSE_OUTPUT,
718             "Constant expression reduced to (STRING) %s\n\n",
719             Op->Common.Value.String);
720         break;
721 
722     case ACPI_TYPE_BUFFER:
723         /*
724          * Create a new parse subtree of the form:
725          *
726          * BUFFER (Buffer AML opcode)
727          *    INTEGER (Buffer length in bytes)
728          *    RAW_DATA (Buffer byte data)
729          */
730         Op->Asl.ParseOpcode = PARSEOP_BUFFER;
731         Op->Common.AmlOpcode = AML_BUFFER_OP;
732         Op->Asl.CompileFlags = OP_AML_PACKAGE;
733         UtSetParseOpName (Op);
734 
735         /* Child node is the buffer length */
736 
737         LengthOp = TrAllocateOp (PARSEOP_INTEGER);
738 
739         LengthOp->Asl.AmlOpcode = AML_DWORD_OP;
740         LengthOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
741         LengthOp->Asl.Parent = Op;
742         (void) OpcSetOptimalIntegerSize (LengthOp);
743 
744         Op->Asl.Child = LengthOp;
745 
746         /* Next child is the raw buffer data */
747 
748         DataOp = TrAllocateOp (PARSEOP_RAW_DATA);
749         DataOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
750         DataOp->Asl.AmlLength = ObjDesc->Buffer.Length;
751         DataOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer;
752         DataOp->Asl.Parent = Op;
753 
754         LengthOp->Asl.Next = DataOp;
755 
756         DbgPrint (ASL_PARSE_OUTPUT,
757             "Constant expression reduced to (BUFFER) length %X\n\n",
758             ObjDesc->Buffer.Length);
759         break;
760 
761     default:
762         break;
763     }
764 }
765 
766 
767 /*******************************************************************************
768  *
769  * FUNCTION:    OpcUpdateIntegerNode
770  *
771  * PARAMETERS:  Op                  - Current parse object
772  *              Value               - Value for the integer op
773  *
774  * RETURN:      None
775  *
776  * DESCRIPTION: Update node to the correct Integer type and value
777  *
778  ******************************************************************************/
779 
780 static void
OpcUpdateIntegerNode(ACPI_PARSE_OBJECT * Op,UINT64 Value)781 OpcUpdateIntegerNode (
782     ACPI_PARSE_OBJECT       *Op,
783     UINT64                  Value)
784 {
785 
786     Op->Common.Value.Integer = Value;
787 
788     /*
789      * The AmlLength is used by the parser to indicate a constant,
790      * (if non-zero). Length is either (1/2/4/8)
791      */
792     switch (Op->Asl.AmlLength)
793     {
794     case 1:
795 
796         TrSetOpIntegerValue (PARSEOP_BYTECONST, Op);
797         Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
798         break;
799 
800     case 2:
801 
802         TrSetOpIntegerValue (PARSEOP_WORDCONST, Op);
803         Op->Asl.AmlOpcode = AML_RAW_DATA_WORD;
804         break;
805 
806     case 4:
807 
808         TrSetOpIntegerValue (PARSEOP_DWORDCONST, Op);
809         Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD;
810         break;
811 
812     case 8:
813 
814         TrSetOpIntegerValue (PARSEOP_QWORDCONST, Op);
815         Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD;
816         break;
817 
818     case 0:
819     default:
820 
821         OpcSetOptimalIntegerSize (Op);
822         TrSetOpIntegerValue (PARSEOP_INTEGER, Op);
823         break;
824     }
825 
826     Op->Asl.AmlLength = 0;
827 }
828 
829 
830 /*******************************************************************************
831  *
832  * FUNCTION:    OpcAmlEvaluationWalk1
833  *
834  * PARAMETERS:  ASL_WALK_CALLBACK
835  *
836  * RETURN:      Status
837  *
838  * DESCRIPTION: Descending callback for AML execution of constant subtrees
839  *
840  ******************************************************************************/
841 
842 static ACPI_STATUS
OpcAmlEvaluationWalk1(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)843 OpcAmlEvaluationWalk1 (
844     ACPI_PARSE_OBJECT       *Op,
845     UINT32                  Level,
846     void                    *Context)
847 {
848     ACPI_WALK_STATE         *WalkState = Context;
849     ACPI_STATUS             Status;
850     ACPI_PARSE_OBJECT       *OutOp;
851 
852 
853     WalkState->Op = Op;
854     WalkState->Opcode = Op->Common.AmlOpcode;
855     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
856 
857     /* Copy child pointer to Arg for compatibility with Interpreter */
858 
859     if (Op->Asl.Child)
860     {
861         Op->Common.Value.Arg = Op->Asl.Child;
862     }
863 
864     /* Call AML dispatcher */
865 
866     Status = AcpiDsExecBeginOp (WalkState, &OutOp);
867     if (ACPI_FAILURE (Status))
868     {
869         DbgPrint (ASL_PARSE_OUTPUT,
870             "%s Constant interpretation failed (1) - %s\n",
871             Op->Asl.ParseOpName, AcpiFormatException (Status));
872     }
873 
874     return (Status);
875 }
876 
877 
878 /*******************************************************************************
879  *
880  * FUNCTION:    OpcAmlEvaluationWalk2
881  *
882  * PARAMETERS:  ASL_WALK_CALLBACK
883  *
884  * RETURN:      Status
885  *
886  * DESCRIPTION: Ascending callback for AML execution of constant subtrees
887  *
888  ******************************************************************************/
889 
890 static ACPI_STATUS
OpcAmlEvaluationWalk2(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)891 OpcAmlEvaluationWalk2 (
892     ACPI_PARSE_OBJECT       *Op,
893     UINT32                  Level,
894     void                    *Context)
895 {
896     ACPI_WALK_STATE         *WalkState = Context;
897     ACPI_STATUS             Status;
898 
899 
900     WalkState->Op = Op;
901     WalkState->Opcode = Op->Common.AmlOpcode;
902     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
903 
904     /* Copy child pointer to Arg for compatibility with Interpreter */
905 
906     if (Op->Asl.Child)
907     {
908         Op->Common.Value.Arg = Op->Asl.Child;
909     }
910 
911     /* Call AML dispatcher */
912 
913     Status = AcpiDsExecEndOp (WalkState);
914     if (ACPI_FAILURE (Status))
915     {
916         DbgPrint (ASL_PARSE_OUTPUT,
917             "%s: Constant interpretation failed (2) - %s\n",
918             Op->Asl.ParseOpName, AcpiFormatException (Status));
919     }
920 
921     return (Status);
922 }
923