]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/dev/acpica/compiler/aslfold.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / dev / acpica / compiler / aslfold.c
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