xref: /freebsd/sys/contrib/dev/acpica/compiler/aslfold.c (revision bb15ca603fa442c72dde3f3cb8b46db6970e3950)
1 
2 /******************************************************************************
3  *
4  * Module Name: aslfold - Constant folding
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2011, Intel Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44 
45 
46 #include <contrib/dev/acpica/compiler/aslcompiler.h>
47 #include "aslcompiler.y.h"
48 #include <contrib/dev/acpica/include/amlcode.h>
49 
50 #include <contrib/dev/acpica/include/acdispat.h>
51 #include <contrib/dev/acpica/include/acparser.h>
52 
53 #define _COMPONENT          ACPI_COMPILER
54         ACPI_MODULE_NAME    ("aslfold")
55 
56 /* Local prototypes */
57 
58 static ACPI_STATUS
59 OpcAmlEvaluationWalk1 (
60     ACPI_PARSE_OBJECT       *Op,
61     UINT32                  Level,
62     void                    *Context);
63 
64 static ACPI_STATUS
65 OpcAmlEvaluationWalk2 (
66     ACPI_PARSE_OBJECT       *Op,
67     UINT32                  Level,
68     void                    *Context);
69 
70 static ACPI_STATUS
71 OpcAmlCheckForConstant (
72     ACPI_PARSE_OBJECT       *Op,
73     UINT32                  Level,
74     void                    *Context);
75 
76 
77 /*******************************************************************************
78  *
79  * FUNCTION:    OpcAmlEvaluationWalk1
80  *
81  * PARAMETERS:  ASL_WALK_CALLBACK
82  *
83  * RETURN:      Status
84  *
85  * DESCRIPTION: Descending callback for AML execution of constant subtrees
86  *
87  ******************************************************************************/
88 
89 static ACPI_STATUS
90 OpcAmlEvaluationWalk1 (
91     ACPI_PARSE_OBJECT       *Op,
92     UINT32                  Level,
93     void                    *Context)
94 {
95     ACPI_WALK_STATE         *WalkState = Context;
96     ACPI_STATUS             Status;
97     ACPI_PARSE_OBJECT       *OutOp;
98 
99 
100     WalkState->Op = Op;
101     WalkState->Opcode = Op->Common.AmlOpcode;
102     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
103 
104     /* Copy child pointer to Arg for compatibility with Interpreter */
105 
106     if (Op->Asl.Child)
107     {
108         Op->Common.Value.Arg = Op->Asl.Child;
109     }
110 
111     /* Call AML dispatcher */
112 
113     Status = AcpiDsExecBeginOp (WalkState, &OutOp);
114     if (ACPI_FAILURE (Status))
115     {
116         AcpiOsPrintf ("Constant interpretation failed - %s\n",
117                         AcpiFormatException (Status));
118     }
119 
120     return (Status);
121 }
122 
123 
124 /*******************************************************************************
125  *
126  * FUNCTION:    OpcAmlEvaluationWalk2
127  *
128  * PARAMETERS:  ASL_WALK_CALLBACK
129  *
130  * RETURN:      Status
131  *
132  * DESCRIPTION: Ascending callback for AML execution of constant subtrees
133  *
134  ******************************************************************************/
135 
136 static ACPI_STATUS
137 OpcAmlEvaluationWalk2 (
138     ACPI_PARSE_OBJECT       *Op,
139     UINT32                  Level,
140     void                    *Context)
141 {
142     ACPI_WALK_STATE         *WalkState = Context;
143     ACPI_STATUS             Status;
144 
145 
146     WalkState->Op = Op;
147     WalkState->Opcode = Op->Common.AmlOpcode;
148     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
149 
150     /* Copy child pointer to Arg for compatibility with Interpreter */
151 
152     if (Op->Asl.Child)
153     {
154         Op->Common.Value.Arg = Op->Asl.Child;
155     }
156 
157     /* Call AML dispatcher */
158 
159     Status = AcpiDsExecEndOp (WalkState);
160     if (ACPI_FAILURE (Status))
161     {
162         AcpiOsPrintf ("Constant interpretation failed - %s\n",
163                         AcpiFormatException (Status));
164     }
165 
166     return (Status);
167 }
168 
169 
170 /*******************************************************************************
171  *
172  * FUNCTION:    OpcAmlCheckForConstant
173  *
174  * PARAMETERS:  ASL_WALK_CALLBACK
175  *
176  * RETURN:      Status
177  *
178  * DESCRIPTION: Check one Op for a type 3/4/5 AML opcode
179  *
180  ******************************************************************************/
181 
182 static ACPI_STATUS
183 OpcAmlCheckForConstant (
184     ACPI_PARSE_OBJECT       *Op,
185     UINT32                  Level,
186     void                    *Context)
187 {
188     ACPI_WALK_STATE         *WalkState = Context;
189 
190 
191     WalkState->Op = Op;
192     WalkState->Opcode = Op->Common.AmlOpcode;
193     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
194 
195     DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ",
196                 Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
197 
198     if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
199     {
200         /* The opcode is not a Type 3/4/5 opcode */
201 
202         if (Op->Asl.CompileFlags & NODE_IS_TARGET)
203         {
204             DbgPrint (ASL_PARSE_OUTPUT,
205                 "**** Valid Target, cannot reduce ****\n");
206         }
207         else
208         {
209             DbgPrint (ASL_PARSE_OUTPUT,
210                 "**** Not a Type 3/4/5 opcode ****\n");
211         }
212 
213         if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
214         {
215             /*
216              * We are looking at at normal expression to see if it can be
217              * reduced.  It can't.  No error
218              */
219             return (AE_TYPE);
220         }
221 
222         /*
223          * This is an expression that MUST reduce to a constant, and it
224          * can't be reduced.  This is an error
225          */
226         if (Op->Asl.CompileFlags & NODE_IS_TARGET)
227         {
228             AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op,
229                 Op->Asl.ParseOpName);
230         }
231         else
232         {
233             AslError (ASL_ERROR, ASL_MSG_INVALID_CONSTANT_OP, Op,
234                 Op->Asl.ParseOpName);
235         }
236 
237         return (AE_TYPE);
238     }
239 
240     /* Debug output */
241 
242     DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345");
243 
244     if (Op->Asl.CompileFlags & NODE_IS_TARGET)
245     {
246         DbgPrint (ASL_PARSE_OUTPUT, " TARGET");
247     }
248     if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
249     {
250         DbgPrint (ASL_PARSE_OUTPUT, " TERMARG");
251     }
252     DbgPrint (ASL_PARSE_OUTPUT, "\n");
253 
254     return (AE_OK);
255 }
256 
257 
258 /*******************************************************************************
259  *
260  * FUNCTION:    OpcAmlConstantWalk
261  *
262  * PARAMETERS:  ASL_WALK_CALLBACK
263  *
264  * RETURN:      Status
265  *
266  * DESCRIPTION: Reduce an Op and its subtree to a constant if possible
267  *
268  ******************************************************************************/
269 
270 ACPI_STATUS
271 OpcAmlConstantWalk (
272     ACPI_PARSE_OBJECT       *Op,
273     UINT32                  Level,
274     void                    *Context)
275 {
276     ACPI_WALK_STATE         *WalkState;
277     ACPI_STATUS             Status = AE_OK;
278     ACPI_OPERAND_OBJECT     *ObjDesc;
279     ACPI_PARSE_OBJECT       *RootOp;
280     ACPI_PARSE_OBJECT       *OriginalParentOp;
281     UINT8                   WalkType;
282 
283 
284     /*
285      * Only interested in subtrees that could possibly contain
286      * expressions that can be evaluated at this time
287      */
288     if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) ||
289           (Op->Asl.CompileFlags & NODE_IS_TARGET))
290     {
291         return (AE_OK);
292     }
293 
294     /* Set the walk type based on the reduction used for this op */
295 
296     if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
297     {
298         /* Op is a TermArg, constant folding is merely optional */
299 
300         if (!Gbl_FoldConstants)
301         {
302             return (AE_CTRL_DEPTH);
303         }
304 
305         WalkType = ACPI_WALK_CONST_OPTIONAL;
306     }
307     else
308     {
309         /* Op is a DataObject, the expression MUST reduced to a constant */
310 
311         WalkType = ACPI_WALK_CONST_REQUIRED;
312     }
313 
314     /* Create a new walk state */
315 
316     WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
317     if (!WalkState)
318     {
319         return AE_NO_MEMORY;
320     }
321 
322     WalkState->NextOp               = NULL;
323     WalkState->Params               = NULL;
324     WalkState->CallerReturnDesc     = &ObjDesc;
325     WalkState->WalkType             = WalkType;
326 
327     /*
328      * Examine the entire subtree -- all nodes must be constants
329      * or type 3/4/5 opcodes
330      */
331     Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
332                 OpcAmlCheckForConstant, NULL, WalkState);
333 
334     /*
335      * Did we find an entire subtree that contains all constants and type 3/4/5
336      * opcodes?  (Only AE_OK or AE_TYPE returned from above)
337      */
338     if (Status == AE_TYPE)
339     {
340         /* Subtree cannot be reduced to a constant */
341 
342         if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
343         {
344             AcpiDsDeleteWalkState (WalkState);
345             return (AE_OK);
346         }
347 
348         /* Don't descend any further, and use a default "constant" value */
349 
350         Status = AE_CTRL_DEPTH;
351     }
352     else
353     {
354         /* Subtree can be reduced */
355 
356         /* Allocate a new temporary root for this subtree */
357 
358         RootOp = TrAllocateNode (PARSEOP_INTEGER);
359         if (!RootOp)
360         {
361             return (AE_NO_MEMORY);
362         }
363 
364         RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
365 
366         OriginalParentOp = Op->Common.Parent;
367         Op->Common.Parent = RootOp;
368 
369         /* Hand off the subtree to the AML interpreter */
370 
371         Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
372                     OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
373         Op->Common.Parent = OriginalParentOp;
374 
375         /* TBD: we really *should* release the RootOp node */
376 
377         if (ACPI_SUCCESS (Status))
378         {
379             TotalFolds++;
380 
381             /* Get the final result */
382 
383             Status = AcpiDsResultPop (&ObjDesc, WalkState);
384         }
385     }
386 
387     if (ACPI_FAILURE (Status))
388     {
389         /* We could not resolve the subtree for some reason */
390 
391         AslCoreSubsystemError (Op, Status,
392             "Failure during constant evaluation", FALSE);
393         AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
394             Op->Asl.ParseOpName);
395 
396         /* Set the subtree value to ZERO anyway.  Eliminates further errors */
397 
398         Op->Asl.ParseOpcode      = PARSEOP_INTEGER;
399         Op->Common.Value.Integer = 0;
400         OpcSetOptimalIntegerSize (Op);
401     }
402     else
403     {
404         AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
405             Op->Asl.ParseOpName);
406 
407         /*
408          * Because we know we executed type 3/4/5 opcodes above, we know that
409          * the result must be either an Integer, String, or Buffer.
410          */
411         switch (ObjDesc->Common.Type)
412         {
413         case ACPI_TYPE_INTEGER:
414 
415             Op->Asl.ParseOpcode      = PARSEOP_INTEGER;
416             Op->Common.Value.Integer = ObjDesc->Integer.Value;
417             OpcSetOptimalIntegerSize (Op);
418 
419             DbgPrint (ASL_PARSE_OUTPUT,
420                 "Constant expression reduced to (INTEGER) %8.8X%8.8X\n",
421                 ACPI_FORMAT_UINT64 (ObjDesc->Integer.Value));
422             break;
423 
424 
425         case ACPI_TYPE_STRING:
426 
427             Op->Asl.ParseOpcode     = PARSEOP_STRING_LITERAL;
428             Op->Common.AmlOpcode    = AML_STRING_OP;
429             Op->Asl.AmlLength       = ACPI_STRLEN (ObjDesc->String.Pointer) + 1;
430             Op->Common.Value.String = ObjDesc->String.Pointer;
431 
432             DbgPrint (ASL_PARSE_OUTPUT,
433                 "Constant expression reduced to (STRING) %s\n",
434                 Op->Common.Value.String);
435 
436             break;
437 
438 
439         case ACPI_TYPE_BUFFER:
440 
441             Op->Asl.ParseOpcode     = PARSEOP_BUFFER;
442             Op->Common.AmlOpcode    = AML_BUFFER_OP;
443             Op->Asl.CompileFlags    = NODE_AML_PACKAGE;
444             UtSetParseOpName (Op);
445 
446             /* Child node is the buffer length */
447 
448             RootOp = TrAllocateNode (PARSEOP_INTEGER);
449 
450             RootOp->Asl.AmlOpcode     = AML_DWORD_OP;
451             RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
452             RootOp->Asl.Parent        = Op;
453 
454             (void) OpcSetOptimalIntegerSize (RootOp);
455 
456             Op->Asl.Child = RootOp;
457             Op = RootOp;
458             UtSetParseOpName (Op);
459 
460             /* Peer to the child is the raw buffer data */
461 
462             RootOp = TrAllocateNode (PARSEOP_RAW_DATA);
463             RootOp->Asl.AmlOpcode     = AML_RAW_DATA_BUFFER;
464             RootOp->Asl.AmlLength     = ObjDesc->Buffer.Length;
465             RootOp->Asl.Value.String  = (char *) ObjDesc->Buffer.Pointer;
466             RootOp->Asl.Parent        = Op->Asl.Parent;
467 
468             Op->Asl.Next = RootOp;
469             Op = RootOp;
470 
471             DbgPrint (ASL_PARSE_OUTPUT,
472                 "Constant expression reduced to (BUFFER) length %X\n",
473                 ObjDesc->Buffer.Length);
474             break;
475 
476 
477         default:
478             printf ("Unsupported return type: %s\n",
479                         AcpiUtGetObjectTypeName (ObjDesc));
480             break;
481         }
482     }
483 
484     UtSetParseOpName (Op);
485     Op->Asl.Child = NULL;
486 
487     AcpiDsDeleteWalkState (WalkState);
488 
489     return (AE_CTRL_DEPTH);
490 }
491 
492