]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/dev/acpica/compiler/aslfold.c
Merge ACPICA 20120913.
[FreeBSD/FreeBSD.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 - 2012, 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 static void
77 OpcUpdateIntegerNode (
78     ACPI_PARSE_OBJECT       *Op,
79     UINT64                  Value);
80
81
82 /*******************************************************************************
83  *
84  * FUNCTION:    OpcAmlEvaluationWalk1
85  *
86  * PARAMETERS:  ASL_WALK_CALLBACK
87  *
88  * RETURN:      Status
89  *
90  * DESCRIPTION: Descending callback for AML execution of constant subtrees
91  *
92  ******************************************************************************/
93
94 static ACPI_STATUS
95 OpcAmlEvaluationWalk1 (
96     ACPI_PARSE_OBJECT       *Op,
97     UINT32                  Level,
98     void                    *Context)
99 {
100     ACPI_WALK_STATE         *WalkState = Context;
101     ACPI_STATUS             Status;
102     ACPI_PARSE_OBJECT       *OutOp;
103
104
105     WalkState->Op = Op;
106     WalkState->Opcode = Op->Common.AmlOpcode;
107     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
108
109     /* Copy child pointer to Arg for compatibility with Interpreter */
110
111     if (Op->Asl.Child)
112     {
113         Op->Common.Value.Arg = Op->Asl.Child;
114     }
115
116     /* Call AML dispatcher */
117
118     Status = AcpiDsExecBeginOp (WalkState, &OutOp);
119     if (ACPI_FAILURE (Status))
120     {
121         AcpiOsPrintf ("Constant interpretation failed - %s\n",
122                         AcpiFormatException (Status));
123     }
124
125     return (Status);
126 }
127
128
129 /*******************************************************************************
130  *
131  * FUNCTION:    OpcAmlEvaluationWalk2
132  *
133  * PARAMETERS:  ASL_WALK_CALLBACK
134  *
135  * RETURN:      Status
136  *
137  * DESCRIPTION: Ascending callback for AML execution of constant subtrees
138  *
139  ******************************************************************************/
140
141 static ACPI_STATUS
142 OpcAmlEvaluationWalk2 (
143     ACPI_PARSE_OBJECT       *Op,
144     UINT32                  Level,
145     void                    *Context)
146 {
147     ACPI_WALK_STATE         *WalkState = Context;
148     ACPI_STATUS             Status;
149
150
151     WalkState->Op = Op;
152     WalkState->Opcode = Op->Common.AmlOpcode;
153     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
154
155     /* Copy child pointer to Arg for compatibility with Interpreter */
156
157     if (Op->Asl.Child)
158     {
159         Op->Common.Value.Arg = Op->Asl.Child;
160     }
161
162     /* Call AML dispatcher */
163
164     Status = AcpiDsExecEndOp (WalkState);
165     if (ACPI_FAILURE (Status))
166     {
167         AcpiOsPrintf ("Constant interpretation failed - %s\n",
168                         AcpiFormatException (Status));
169     }
170
171     return (Status);
172 }
173
174
175 /*******************************************************************************
176  *
177  * FUNCTION:    OpcAmlCheckForConstant
178  *
179  * PARAMETERS:  ASL_WALK_CALLBACK
180  *
181  * RETURN:      Status
182  *
183  * DESCRIPTION: Check one Op for a type 3/4/5 AML opcode
184  *
185  ******************************************************************************/
186
187 static ACPI_STATUS
188 OpcAmlCheckForConstant (
189     ACPI_PARSE_OBJECT       *Op,
190     UINT32                  Level,
191     void                    *Context)
192 {
193     ACPI_WALK_STATE         *WalkState = Context;
194
195
196     WalkState->Op = Op;
197     WalkState->Opcode = Op->Common.AmlOpcode;
198     WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
199
200     DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ",
201                 Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
202
203     /*
204      * These opcodes do not appear in the OpcodeInfo table, but
205      * they represent constants, so abort the constant walk now.
206      */
207     if ((WalkState->Opcode == AML_RAW_DATA_BYTE) ||
208         (WalkState->Opcode == AML_RAW_DATA_WORD) ||
209         (WalkState->Opcode == AML_RAW_DATA_DWORD) ||
210         (WalkState->Opcode == AML_RAW_DATA_QWORD))
211     {
212         WalkState->WalkType = ACPI_WALK_CONST_OPTIONAL;
213         return (AE_TYPE);
214     }
215
216     if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
217     {
218         /* The opcode is not a Type 3/4/5 opcode */
219
220         if (Op->Asl.CompileFlags & NODE_IS_TARGET)
221         {
222             DbgPrint (ASL_PARSE_OUTPUT,
223                 "**** Valid Target, cannot reduce ****\n");
224         }
225         else
226         {
227             DbgPrint (ASL_PARSE_OUTPUT,
228                 "**** Not a Type 3/4/5 opcode ****\n");
229         }
230
231         if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
232         {
233             /*
234              * We are looking at at normal expression to see if it can be
235              * reduced. It can't. No error
236              */
237             return (AE_TYPE);
238         }
239
240         /*
241          * This is an expression that MUST reduce to a constant, and it
242          * can't be reduced. This is an error
243          */
244         if (Op->Asl.CompileFlags & NODE_IS_TARGET)
245         {
246             AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op,
247                 Op->Asl.ParseOpName);
248         }
249         else
250         {
251             AslError (ASL_ERROR, ASL_MSG_INVALID_CONSTANT_OP, Op,
252                 Op->Asl.ParseOpName);
253         }
254
255         return (AE_TYPE);
256     }
257
258     /* Debug output */
259
260     DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345");
261
262     if (Op->Asl.CompileFlags & NODE_IS_TARGET)
263     {
264         DbgPrint (ASL_PARSE_OUTPUT, " TARGET");
265     }
266     if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
267     {
268         DbgPrint (ASL_PARSE_OUTPUT, " TERMARG");
269     }
270
271     DbgPrint (ASL_PARSE_OUTPUT, "\n");
272     return (AE_OK);
273 }
274
275
276 /*******************************************************************************
277  *
278  * FUNCTION:    OpcAmlConstantWalk
279  *
280  * PARAMETERS:  ASL_WALK_CALLBACK
281  *
282  * RETURN:      Status
283  *
284  * DESCRIPTION: Reduce an Op and its subtree to a constant if possible
285  *
286  ******************************************************************************/
287
288 ACPI_STATUS
289 OpcAmlConstantWalk (
290     ACPI_PARSE_OBJECT       *Op,
291     UINT32                  Level,
292     void                    *Context)
293 {
294     ACPI_WALK_STATE         *WalkState;
295     ACPI_STATUS             Status = AE_OK;
296     ACPI_OPERAND_OBJECT     *ObjDesc;
297     ACPI_PARSE_OBJECT       *RootOp;
298     ACPI_PARSE_OBJECT       *OriginalParentOp;
299     UINT8                   WalkType;
300
301
302     /*
303      * Only interested in subtrees that could possibly contain
304      * expressions that can be evaluated at this time
305      */
306     if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) ||
307           (Op->Asl.CompileFlags & NODE_IS_TARGET))
308     {
309         return (AE_OK);
310     }
311
312     /* Set the walk type based on the reduction used for this op */
313
314     if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
315     {
316         /* Op is a TermArg, constant folding is merely optional */
317
318         if (!Gbl_FoldConstants)
319         {
320             return (AE_CTRL_DEPTH);
321         }
322
323         WalkType = ACPI_WALK_CONST_OPTIONAL;
324     }
325     else
326     {
327         /* Op is a DataObject, the expression MUST reduced to a constant */
328
329         WalkType = ACPI_WALK_CONST_REQUIRED;
330     }
331
332     /* Create a new walk state */
333
334     WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
335     if (!WalkState)
336     {
337         return AE_NO_MEMORY;
338     }
339
340     WalkState->NextOp = NULL;
341     WalkState->Params = NULL;
342     WalkState->WalkType = WalkType;
343     WalkState->CallerReturnDesc = &ObjDesc;
344
345     /*
346      * Examine the entire subtree -- all nodes must be constants
347      * or type 3/4/5 opcodes
348      */
349     Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
350         OpcAmlCheckForConstant, NULL, WalkState);
351
352     /*
353      * Did we find an entire subtree that contains all constants and type 3/4/5
354      * opcodes?  (Only AE_OK or AE_TYPE returned from above)
355      */
356     if (Status == AE_TYPE)
357     {
358         /* Subtree cannot be reduced to a constant */
359
360         if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
361         {
362             AcpiDsDeleteWalkState (WalkState);
363             return (AE_OK);
364         }
365
366         /* Don't descend any further, and use a default "constant" value */
367
368         Status = AE_CTRL_DEPTH;
369     }
370     else
371     {
372         /* Subtree can be reduced */
373
374         /* Allocate a new temporary root for this subtree */
375
376         RootOp = TrAllocateNode (PARSEOP_INTEGER);
377         if (!RootOp)
378         {
379             return (AE_NO_MEMORY);
380         }
381
382         RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
383
384         OriginalParentOp = Op->Common.Parent;
385         Op->Common.Parent = RootOp;
386
387         /* Hand off the subtree to the AML interpreter */
388
389         Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
390             OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
391         Op->Common.Parent = OriginalParentOp;
392
393         /* TBD: we really *should* release the RootOp node */
394
395         if (ACPI_SUCCESS (Status))
396         {
397             TotalFolds++;
398
399             /* Get the final result */
400
401             Status = AcpiDsResultPop (&ObjDesc, WalkState);
402         }
403
404         /* Check for error from the ACPICA core */
405
406         if (ACPI_FAILURE (Status))
407         {
408             AslCoreSubsystemError (Op, Status,
409                 "Failure during constant evaluation", FALSE);
410         }
411     }
412
413     if (ACPI_FAILURE (Status))
414     {
415         /* We could not resolve the subtree for some reason */
416
417         AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
418             Op->Asl.ParseOpName);
419
420         /* Set the subtree value to ZERO anyway. Eliminates further errors */
421
422         OpcUpdateIntegerNode (Op, 0);
423     }
424     else
425     {
426         AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
427             Op->Asl.ParseOpName);
428
429         /*
430          * Because we know we executed type 3/4/5 opcodes above, we know that
431          * the result must be either an Integer, String, or Buffer.
432          */
433         switch (ObjDesc->Common.Type)
434         {
435         case ACPI_TYPE_INTEGER:
436
437             OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value);
438
439             DbgPrint (ASL_PARSE_OUTPUT,
440                 "Constant expression reduced to (%s) %8.8X%8.8X\n",
441                 Op->Asl.ParseOpName,
442                 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
443             break;
444
445
446         case ACPI_TYPE_STRING:
447
448             Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
449             Op->Common.AmlOpcode = AML_STRING_OP;
450             Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1;
451             Op->Common.Value.String = ObjDesc->String.Pointer;
452
453             DbgPrint (ASL_PARSE_OUTPUT,
454                 "Constant expression reduced to (STRING) %s\n",
455                 Op->Common.Value.String);
456
457             break;
458
459
460         case ACPI_TYPE_BUFFER:
461
462             Op->Asl.ParseOpcode = PARSEOP_BUFFER;
463             Op->Common.AmlOpcode = AML_BUFFER_OP;
464             Op->Asl.CompileFlags = NODE_AML_PACKAGE;
465             UtSetParseOpName (Op);
466
467             /* Child node is the buffer length */
468
469             RootOp = TrAllocateNode (PARSEOP_INTEGER);
470
471             RootOp->Asl.AmlOpcode = AML_DWORD_OP;
472             RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
473             RootOp->Asl.Parent = Op;
474
475             (void) OpcSetOptimalIntegerSize (RootOp);
476
477             Op->Asl.Child = RootOp;
478             Op = RootOp;
479             UtSetParseOpName (Op);
480
481             /* Peer to the child is the raw buffer data */
482
483             RootOp = TrAllocateNode (PARSEOP_RAW_DATA);
484             RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
485             RootOp->Asl.AmlLength = ObjDesc->Buffer.Length;
486             RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer;
487             RootOp->Asl.Parent = Op->Asl.Parent;
488
489             Op->Asl.Next = RootOp;
490             Op = RootOp;
491
492             DbgPrint (ASL_PARSE_OUTPUT,
493                 "Constant expression reduced to (BUFFER) length %X\n",
494                 ObjDesc->Buffer.Length);
495             break;
496
497
498         default:
499             printf ("Unsupported return type: %s\n",
500                 AcpiUtGetObjectTypeName (ObjDesc));
501             break;
502         }
503     }
504
505     UtSetParseOpName (Op);
506     Op->Asl.Child = NULL;
507
508     AcpiDsDeleteWalkState (WalkState);
509     return (AE_CTRL_DEPTH);
510 }
511
512
513 /*******************************************************************************
514  *
515  * FUNCTION:    OpcUpdateIntegerNode
516  *
517  * PARAMETERS:  Op                  - Current parse object
518  *
519  * RETURN:      None
520  *
521  * DESCRIPTION: Update node to the correct integer type.
522  *
523  ******************************************************************************/
524
525 static void
526 OpcUpdateIntegerNode (
527     ACPI_PARSE_OBJECT       *Op,
528     UINT64                  Value)
529 {
530
531     Op->Common.Value.Integer = Value;
532
533     /*
534      * The AmlLength is used by the parser to indicate a constant,
535      * (if non-zero). Length is either (1/2/4/8)
536      */
537     switch (Op->Asl.AmlLength)
538     {
539     case 1:
540         TrUpdateNode (PARSEOP_BYTECONST, Op);
541         Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
542         break;
543
544     case 2:
545         TrUpdateNode (PARSEOP_WORDCONST, Op);
546         Op->Asl.AmlOpcode = AML_RAW_DATA_WORD;
547         break;
548
549     case 4:
550         TrUpdateNode (PARSEOP_DWORDCONST, Op);
551         Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD;
552         break;
553
554     case 8:
555         TrUpdateNode (PARSEOP_QWORDCONST, Op);
556         Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD;
557         break;
558
559     case 0:
560     default:
561         OpcSetOptimalIntegerSize (Op);
562         TrUpdateNode (PARSEOP_INTEGER, Op);
563         break;
564     }
565
566     Op->Asl.AmlLength = 0;
567 }