aslfold.c revision 250838
1/******************************************************************************
2 *
3 * Module Name: aslfold - Constant folding
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, 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
57static ACPI_STATUS
58OpcAmlEvaluationWalk1 (
59    ACPI_PARSE_OBJECT       *Op,
60    UINT32                  Level,
61    void                    *Context);
62
63static ACPI_STATUS
64OpcAmlEvaluationWalk2 (
65    ACPI_PARSE_OBJECT       *Op,
66    UINT32                  Level,
67    void                    *Context);
68
69static ACPI_STATUS
70OpcAmlCheckForConstant (
71    ACPI_PARSE_OBJECT       *Op,
72    UINT32                  Level,
73    void                    *Context);
74
75static void
76OpcUpdateIntegerNode (
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
93static ACPI_STATUS
94OpcAmlEvaluationWalk1 (
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
140static ACPI_STATUS
141OpcAmlEvaluationWalk2 (
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
186static ACPI_STATUS
187OpcAmlCheckForConstant (
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
287ACPI_STATUS
288OpcAmlConstantWalk (
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        case ACPI_TYPE_STRING:
445
446            Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
447            Op->Common.AmlOpcode = AML_STRING_OP;
448            Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1;
449            Op->Common.Value.String = ObjDesc->String.Pointer;
450
451            DbgPrint (ASL_PARSE_OUTPUT,
452                "Constant expression reduced to (STRING) %s\n",
453                Op->Common.Value.String);
454
455            break;
456
457        case ACPI_TYPE_BUFFER:
458
459            Op->Asl.ParseOpcode = PARSEOP_BUFFER;
460            Op->Common.AmlOpcode = AML_BUFFER_OP;
461            Op->Asl.CompileFlags = NODE_AML_PACKAGE;
462            UtSetParseOpName (Op);
463
464            /* Child node is the buffer length */
465
466            RootOp = TrAllocateNode (PARSEOP_INTEGER);
467
468            RootOp->Asl.AmlOpcode = AML_DWORD_OP;
469            RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
470            RootOp->Asl.Parent = Op;
471
472            (void) OpcSetOptimalIntegerSize (RootOp);
473
474            Op->Asl.Child = RootOp;
475            Op = RootOp;
476            UtSetParseOpName (Op);
477
478            /* Peer to the child is the raw buffer data */
479
480            RootOp = TrAllocateNode (PARSEOP_RAW_DATA);
481            RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
482            RootOp->Asl.AmlLength = ObjDesc->Buffer.Length;
483            RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer;
484            RootOp->Asl.Parent = Op->Asl.Parent;
485
486            Op->Asl.Next = RootOp;
487            Op = RootOp;
488
489            DbgPrint (ASL_PARSE_OUTPUT,
490                "Constant expression reduced to (BUFFER) length %X\n",
491                ObjDesc->Buffer.Length);
492            break;
493
494        default:
495
496            printf ("Unsupported return type: %s\n",
497                AcpiUtGetObjectTypeName (ObjDesc));
498            break;
499        }
500    }
501
502    UtSetParseOpName (Op);
503    Op->Asl.Child = NULL;
504
505    AcpiDsDeleteWalkState (WalkState);
506    return (AE_CTRL_DEPTH);
507}
508
509
510/*******************************************************************************
511 *
512 * FUNCTION:    OpcUpdateIntegerNode
513 *
514 * PARAMETERS:  Op                  - Current parse object
515 *
516 * RETURN:      None
517 *
518 * DESCRIPTION: Update node to the correct integer type.
519 *
520 ******************************************************************************/
521
522static void
523OpcUpdateIntegerNode (
524    ACPI_PARSE_OBJECT       *Op,
525    UINT64                  Value)
526{
527
528    Op->Common.Value.Integer = Value;
529
530    /*
531     * The AmlLength is used by the parser to indicate a constant,
532     * (if non-zero). Length is either (1/2/4/8)
533     */
534    switch (Op->Asl.AmlLength)
535    {
536    case 1:
537
538        TrUpdateNode (PARSEOP_BYTECONST, Op);
539        Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
540        break;
541
542    case 2:
543
544        TrUpdateNode (PARSEOP_WORDCONST, Op);
545        Op->Asl.AmlOpcode = AML_RAW_DATA_WORD;
546        break;
547
548    case 4:
549
550        TrUpdateNode (PARSEOP_DWORDCONST, Op);
551        Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD;
552        break;
553
554    case 8:
555
556        TrUpdateNode (PARSEOP_QWORDCONST, Op);
557        Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD;
558        break;
559
560    case 0:
561    default:
562
563        OpcSetOptimalIntegerSize (Op);
564        TrUpdateNode (PARSEOP_INTEGER, Op);
565        break;
566    }
567
568    Op->Asl.AmlLength = 0;
569}
570