aslfold.c revision 217365
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
58static ACPI_STATUS
59OpcAmlEvaluationWalk1 (
60    ACPI_PARSE_OBJECT       *Op,
61    UINT32                  Level,
62    void                    *Context);
63
64static ACPI_STATUS
65OpcAmlEvaluationWalk2 (
66    ACPI_PARSE_OBJECT       *Op,
67    UINT32                  Level,
68    void                    *Context);
69
70static ACPI_STATUS
71OpcAmlCheckForConstant (
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
89static ACPI_STATUS
90OpcAmlEvaluationWalk1 (
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
136static ACPI_STATUS
137OpcAmlEvaluationWalk2 (
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
182static ACPI_STATUS
183OpcAmlCheckForConstant (
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
270ACPI_STATUS
271OpcAmlConstantWalk (
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