xref: /freebsd/sys/contrib/dev/acpica/compiler/aslfold.c (revision ab6f3bf9cb8ad195aecd9165d8d4b1a93aed3c8d)
1 
2 /******************************************************************************
3  *
4  * Module Name: aslfold - Constant folding
5  *
6  *****************************************************************************/
7 
8 /******************************************************************************
9  *
10  * 1. Copyright Notice
11  *
12  * Some or all of this work - Copyright (c) 1999 - 2009, Intel Corp.
13  * All rights reserved.
14  *
15  * 2. License
16  *
17  * 2.1. This is your license from Intel Corp. under its intellectual property
18  * rights.  You may have additional license terms from the party that provided
19  * you this software, covering your right to use that party's intellectual
20  * property rights.
21  *
22  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
23  * copy of the source code appearing in this file ("Covered Code") an
24  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
25  * base code distributed originally by Intel ("Original Intel Code") to copy,
26  * make derivatives, distribute, use and display any portion of the Covered
27  * Code in any form, with the right to sublicense such rights; and
28  *
29  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
30  * license (with the right to sublicense), under only those claims of Intel
31  * patents that are infringed by the Original Intel Code, to make, use, sell,
32  * offer to sell, and import the Covered Code and derivative works thereof
33  * solely to the minimum extent necessary to exercise the above copyright
34  * license, and in no event shall the patent license extend to any additions
35  * to or modifications of the Original Intel Code.  No other license or right
36  * is granted directly or by implication, estoppel or otherwise;
37  *
38  * The above copyright and patent license is granted only if the following
39  * conditions are met:
40  *
41  * 3. Conditions
42  *
43  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
44  * Redistribution of source code of any substantial portion of the Covered
45  * Code or modification with rights to further distribute source must include
46  * the above Copyright Notice, the above License, this list of Conditions,
47  * and the following Disclaimer and Export Compliance provision.  In addition,
48  * Licensee must cause all Covered Code to which Licensee contributes to
49  * contain a file documenting the changes Licensee made to create that Covered
50  * Code and the date of any change.  Licensee must include in that file the
51  * documentation of any changes made by any predecessor Licensee.  Licensee
52  * must include a prominent statement that the modification is derived,
53  * directly or indirectly, from Original Intel Code.
54  *
55  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
56  * Redistribution of source code of any substantial portion of the Covered
57  * Code or modification without rights to further distribute source must
58  * include the following Disclaimer and Export Compliance provision in the
59  * documentation and/or other materials provided with distribution.  In
60  * addition, Licensee may not authorize further sublicense of source of any
61  * portion of the Covered Code, and must include terms to the effect that the
62  * license from Licensee to its licensee is limited to the intellectual
63  * property embodied in the software Licensee provides to its licensee, and
64  * not to intellectual property embodied in modifications its licensee may
65  * make.
66  *
67  * 3.3. Redistribution of Executable. Redistribution in executable form of any
68  * substantial portion of the Covered Code or modification must reproduce the
69  * above Copyright Notice, and the following Disclaimer and Export Compliance
70  * provision in the documentation and/or other materials provided with the
71  * distribution.
72  *
73  * 3.4. Intel retains all right, title, and interest in and to the Original
74  * Intel Code.
75  *
76  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
77  * Intel shall be used in advertising or otherwise to promote the sale, use or
78  * other dealings in products derived from or relating to the Covered Code
79  * without prior written authorization from Intel.
80  *
81  * 4. Disclaimer and Export Compliance
82  *
83  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
84  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
85  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
86  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
87  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
88  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
89  * PARTICULAR PURPOSE.
90  *
91  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
92  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
93  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
94  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
95  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
96  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
97  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
98  * LIMITED REMEDY.
99  *
100  * 4.3. Licensee shall not export, either directly or indirectly, any of this
101  * software or system incorporating such software without first obtaining any
102  * required license or other approval from the U. S. Department of Commerce or
103  * any other agency or department of the United States Government.  In the
104  * event Licensee exports any such software from the United States or
105  * re-exports any such software from a foreign destination, Licensee shall
106  * ensure that the distribution and export/re-export of the software is in
107  * compliance with all laws, regulations, orders, or other restrictions of the
108  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
109  * any of its subsidiaries will export/re-export any technical data, process,
110  * software, or service, directly or indirectly, to any country for which the
111  * United States government or any agency thereof requires an export license,
112  * other governmental approval, or letter of assurance, without first obtaining
113  * such license, approval or letter.
114  *
115  *****************************************************************************/
116 
117 
118 #include <contrib/dev/acpica/compiler/aslcompiler.h>
119 #include "aslcompiler.y.h"
120 #include <contrib/dev/acpica/include/amlcode.h>
121 
122 #include <contrib/dev/acpica/include/acdispat.h>
123 #include <contrib/dev/acpica/include/acparser.h>
124 
125 #define _COMPONENT          ACPI_COMPILER
126         ACPI_MODULE_NAME    ("aslfold")
127 
128 /* Local prototypes */
129 
130 static ACPI_STATUS
131 OpcAmlEvaluationWalk1 (
132     ACPI_PARSE_OBJECT       *Op,
133     UINT32                  Level,
134     void                    *Context);
135 
136 static ACPI_STATUS
137 OpcAmlEvaluationWalk2 (
138     ACPI_PARSE_OBJECT       *Op,
139     UINT32                  Level,
140     void                    *Context);
141 
142 static ACPI_STATUS
143 OpcAmlCheckForConstant (
144     ACPI_PARSE_OBJECT       *Op,
145     UINT32                  Level,
146     void                    *Context);
147 
148 
149 /*******************************************************************************
150  *
151  * FUNCTION:    OpcAmlEvaluationWalk1
152  *
153  * PARAMETERS:  ASL_WALK_CALLBACK
154  *
155  * RETURN:      Status
156  *
157  * DESCRIPTION: Descending callback for AML execution of constant subtrees
158  *
159  ******************************************************************************/
160 
161 static ACPI_STATUS
162 OpcAmlEvaluationWalk1 (
163     ACPI_PARSE_OBJECT       *Op,
164     UINT32                  Level,
165     void                    *Context)
166 {
167     ACPI_WALK_STATE         *WalkState = Context;
168     ACPI_STATUS             Status;
169     ACPI_PARSE_OBJECT       *OutOp;
170 
171 
172     WalkState->Op = Op;
173     WalkState->Opcode = Op->Common.AmlOpcode;
174     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
175 
176     /* Copy child pointer to Arg for compatibility with Interpreter */
177 
178     if (Op->Asl.Child)
179     {
180         Op->Common.Value.Arg = Op->Asl.Child;
181     }
182 
183     /* Call AML dispatcher */
184 
185     Status = AcpiDsExecBeginOp (WalkState, &OutOp);
186     if (ACPI_FAILURE (Status))
187     {
188         AcpiOsPrintf ("Constant interpretation failed - %s\n",
189                         AcpiFormatException (Status));
190     }
191 
192     return (Status);
193 }
194 
195 
196 /*******************************************************************************
197  *
198  * FUNCTION:    OpcAmlEvaluationWalk2
199  *
200  * PARAMETERS:  ASL_WALK_CALLBACK
201  *
202  * RETURN:      Status
203  *
204  * DESCRIPTION: Ascending callback for AML execution of constant subtrees
205  *
206  ******************************************************************************/
207 
208 static ACPI_STATUS
209 OpcAmlEvaluationWalk2 (
210     ACPI_PARSE_OBJECT       *Op,
211     UINT32                  Level,
212     void                    *Context)
213 {
214     ACPI_WALK_STATE         *WalkState = Context;
215     ACPI_STATUS             Status;
216 
217 
218     WalkState->Op = Op;
219     WalkState->Opcode = Op->Common.AmlOpcode;
220     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
221 
222     /* Copy child pointer to Arg for compatibility with Interpreter */
223 
224     if (Op->Asl.Child)
225     {
226         Op->Common.Value.Arg = Op->Asl.Child;
227     }
228 
229     /* Call AML dispatcher */
230 
231     Status = AcpiDsExecEndOp (WalkState);
232     if (ACPI_FAILURE (Status))
233     {
234         AcpiOsPrintf ("Constant interpretation failed - %s\n",
235                         AcpiFormatException (Status));
236     }
237 
238     return (Status);
239 }
240 
241 
242 /*******************************************************************************
243  *
244  * FUNCTION:    OpcAmlCheckForConstant
245  *
246  * PARAMETERS:  ASL_WALK_CALLBACK
247  *
248  * RETURN:      Status
249  *
250  * DESCRIPTION: Check one Op for a type 3/4/5 AML opcode
251  *
252  ******************************************************************************/
253 
254 static ACPI_STATUS
255 OpcAmlCheckForConstant (
256     ACPI_PARSE_OBJECT       *Op,
257     UINT32                  Level,
258     void                    *Context)
259 {
260     ACPI_WALK_STATE         *WalkState = Context;
261 
262 
263     WalkState->Op = Op;
264     WalkState->Opcode = Op->Common.AmlOpcode;
265     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
266 
267     DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ",
268                 Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
269 
270     if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
271     {
272         /* The opcode is not a Type 3/4/5 opcode */
273 
274         if (Op->Asl.CompileFlags & NODE_IS_TARGET)
275         {
276             DbgPrint (ASL_PARSE_OUTPUT,
277                 "**** Valid Target, cannot reduce ****\n");
278         }
279         else
280         {
281             DbgPrint (ASL_PARSE_OUTPUT,
282                 "**** Not a Type 3/4/5 opcode ****\n");
283         }
284 
285         if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
286         {
287             /*
288              * We are looking at at normal expression to see if it can be
289              * reduced.  It can't.  No error
290              */
291             return (AE_TYPE);
292         }
293 
294         /*
295          * This is an expression that MUST reduce to a constant, and it
296          * can't be reduced.  This is an error
297          */
298         if (Op->Asl.CompileFlags & NODE_IS_TARGET)
299         {
300             AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op,
301                 Op->Asl.ParseOpName);
302         }
303         else
304         {
305             AslError (ASL_ERROR, ASL_MSG_INVALID_CONSTANT_OP, Op,
306                 Op->Asl.ParseOpName);
307         }
308 
309         return (AE_TYPE);
310     }
311 
312     /* Debug output */
313 
314     DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345");
315 
316     if (Op->Asl.CompileFlags & NODE_IS_TARGET)
317     {
318         DbgPrint (ASL_PARSE_OUTPUT, " TARGET");
319     }
320     if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
321     {
322         DbgPrint (ASL_PARSE_OUTPUT, " TERMARG");
323     }
324     DbgPrint (ASL_PARSE_OUTPUT, "\n");
325 
326     return (AE_OK);
327 }
328 
329 
330 /*******************************************************************************
331  *
332  * FUNCTION:    OpcAmlConstantWalk
333  *
334  * PARAMETERS:  ASL_WALK_CALLBACK
335  *
336  * RETURN:      Status
337  *
338  * DESCRIPTION: Reduce an Op and its subtree to a constant if possible
339  *
340  ******************************************************************************/
341 
342 ACPI_STATUS
343 OpcAmlConstantWalk (
344     ACPI_PARSE_OBJECT       *Op,
345     UINT32                  Level,
346     void                    *Context)
347 {
348     ACPI_WALK_STATE         *WalkState;
349     ACPI_STATUS             Status = AE_OK;
350     ACPI_OPERAND_OBJECT     *ObjDesc;
351     ACPI_PARSE_OBJECT       *RootOp;
352     ACPI_PARSE_OBJECT       *OriginalParentOp;
353     UINT8                   WalkType;
354 
355 
356     /*
357      * Only interested in subtrees that could possibly contain
358      * expressions that can be evaluated at this time
359      */
360     if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) ||
361           (Op->Asl.CompileFlags & NODE_IS_TARGET))
362     {
363         return (AE_OK);
364     }
365 
366     /* Set the walk type based on the reduction used for this op */
367 
368     if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
369     {
370         /* Op is a TermArg, constant folding is merely optional */
371 
372         if (!Gbl_FoldConstants)
373         {
374             return (AE_CTRL_DEPTH);
375         }
376 
377         WalkType = ACPI_WALK_CONST_OPTIONAL;
378     }
379     else
380     {
381         /* Op is a DataObject, the expression MUST reduced to a constant */
382 
383         WalkType = ACPI_WALK_CONST_REQUIRED;
384     }
385 
386     /* Create a new walk state */
387 
388     WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
389     if (!WalkState)
390     {
391         return AE_NO_MEMORY;
392     }
393 
394     WalkState->NextOp               = NULL;
395     WalkState->Params               = NULL;
396     WalkState->CallerReturnDesc     = &ObjDesc;
397     WalkState->WalkType             = WalkType;
398 
399     /*
400      * Examine the entire subtree -- all nodes must be constants
401      * or type 3/4/5 opcodes
402      */
403     Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
404                 OpcAmlCheckForConstant, NULL, WalkState);
405 
406     /*
407      * Did we find an entire subtree that contains all constants and type 3/4/5
408      * opcodes?  (Only AE_OK or AE_TYPE returned from above)
409      */
410     if (Status == AE_TYPE)
411     {
412         /* Subtree cannot be reduced to a constant */
413 
414         if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
415         {
416             AcpiDsDeleteWalkState (WalkState);
417             return (AE_OK);
418         }
419 
420         /* Don't descend any further, and use a default "constant" value */
421 
422         Status = AE_CTRL_DEPTH;
423     }
424     else
425     {
426         /* Subtree can be reduced */
427 
428         /* Allocate a new temporary root for this subtree */
429 
430         RootOp = TrAllocateNode (PARSEOP_INTEGER);
431         if (!RootOp)
432         {
433             return (AE_NO_MEMORY);
434         }
435 
436         RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
437 
438         OriginalParentOp = Op->Common.Parent;
439         Op->Common.Parent = RootOp;
440 
441         /* Hand off the subtree to the AML interpreter */
442 
443         Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
444                     OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
445         Op->Common.Parent = OriginalParentOp;
446 
447         /* TBD: we really *should* release the RootOp node */
448 
449         if (ACPI_SUCCESS (Status))
450         {
451             TotalFolds++;
452 
453             /* Get the final result */
454 
455             Status = AcpiDsResultPop (&ObjDesc, WalkState);
456         }
457     }
458 
459     if (ACPI_FAILURE (Status))
460     {
461         /* We could not resolve the subtree for some reason */
462 
463         AslCoreSubsystemError (Op, Status,
464             "Failure during constant evaluation", FALSE);
465         AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
466             Op->Asl.ParseOpName);
467 
468         /* Set the subtree value to ZERO anyway.  Eliminates further errors */
469 
470         Op->Asl.ParseOpcode      = PARSEOP_INTEGER;
471         Op->Common.Value.Integer = 0;
472         OpcSetOptimalIntegerSize (Op);
473     }
474     else
475     {
476         AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
477             Op->Asl.ParseOpName);
478 
479         /*
480          * Because we know we executed type 3/4/5 opcodes above, we know that
481          * the result must be either an Integer, String, or Buffer.
482          */
483         switch (ObjDesc->Common.Type)
484         {
485         case ACPI_TYPE_INTEGER:
486 
487             Op->Asl.ParseOpcode      = PARSEOP_INTEGER;
488             Op->Common.Value.Integer = ObjDesc->Integer.Value;
489             OpcSetOptimalIntegerSize (Op);
490 
491             DbgPrint (ASL_PARSE_OUTPUT,
492                 "Constant expression reduced to (INTEGER) %8.8X%8.8X\n",
493                 ACPI_FORMAT_UINT64 (ObjDesc->Integer.Value));
494             break;
495 
496 
497         case ACPI_TYPE_STRING:
498 
499             Op->Asl.ParseOpcode     = PARSEOP_STRING_LITERAL;
500             Op->Common.AmlOpcode    = AML_STRING_OP;
501             Op->Asl.AmlLength       = ACPI_STRLEN (ObjDesc->String.Pointer) + 1;
502             Op->Common.Value.String = ObjDesc->String.Pointer;
503 
504             DbgPrint (ASL_PARSE_OUTPUT,
505                 "Constant expression reduced to (STRING) %s\n",
506                 Op->Common.Value.String);
507 
508             break;
509 
510 
511         case ACPI_TYPE_BUFFER:
512 
513             Op->Asl.ParseOpcode     = PARSEOP_BUFFER;
514             Op->Common.AmlOpcode    = AML_BUFFER_OP;
515             Op->Asl.CompileFlags    = NODE_AML_PACKAGE;
516             UtSetParseOpName (Op);
517 
518             /* Child node is the buffer length */
519 
520             RootOp = TrAllocateNode (PARSEOP_INTEGER);
521 
522             RootOp->Asl.AmlOpcode     = AML_DWORD_OP;
523             RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
524             RootOp->Asl.Parent        = Op;
525 
526             (void) OpcSetOptimalIntegerSize (RootOp);
527 
528             Op->Asl.Child = RootOp;
529             Op = RootOp;
530             UtSetParseOpName (Op);
531 
532             /* Peer to the child is the raw buffer data */
533 
534             RootOp = TrAllocateNode (PARSEOP_RAW_DATA);
535             RootOp->Asl.AmlOpcode     = AML_RAW_DATA_BUFFER;
536             RootOp->Asl.AmlLength     = ObjDesc->Buffer.Length;
537             RootOp->Asl.Value.String  = (char *) ObjDesc->Buffer.Pointer;
538             RootOp->Asl.Parent        = Op->Asl.Parent;
539 
540             Op->Asl.Next = RootOp;
541             Op = RootOp;
542 
543             DbgPrint (ASL_PARSE_OUTPUT,
544                 "Constant expression reduced to (BUFFER) length %X\n",
545                 ObjDesc->Buffer.Length);
546             break;
547 
548 
549         default:
550             printf ("Unsupported return type: %s\n",
551                         AcpiUtGetObjectTypeName (ObjDesc));
552             break;
553         }
554     }
555 
556     UtSetParseOpName (Op);
557     Op->Asl.Child = NULL;
558 
559     AcpiDsDeleteWalkState (WalkState);
560 
561     return (AE_CTRL_DEPTH);
562 }
563 
564