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