1118611Snjl/******************************************************************************
2118611Snjl *
3118611Snjl * Module Name: aslfold - Constant folding
4118611Snjl *
5118611Snjl *****************************************************************************/
6118611Snjl
7217365Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
9118611Snjl * All rights reserved.
10118611Snjl *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
25118611Snjl *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
29118611Snjl *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
43118611Snjl
44151937Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h>
45118611Snjl#include "aslcompiler.y.h"
46193529Sjkim#include <contrib/dev/acpica/include/amlcode.h>
47118611Snjl
48193529Sjkim#include <contrib/dev/acpica/include/acdispat.h>
49193529Sjkim#include <contrib/dev/acpica/include/acparser.h>
50118611Snjl
51118611Snjl#define _COMPONENT          ACPI_COMPILER
52118611Snjl        ACPI_MODULE_NAME    ("aslfold")
53118611Snjl
54151937Sjkim/* Local prototypes */
55118611Snjl
56151937Sjkimstatic ACPI_STATUS
57151937SjkimOpcAmlEvaluationWalk1 (
58151937Sjkim    ACPI_PARSE_OBJECT       *Op,
59151937Sjkim    UINT32                  Level,
60151937Sjkim    void                    *Context);
61151937Sjkim
62151937Sjkimstatic ACPI_STATUS
63151937SjkimOpcAmlEvaluationWalk2 (
64151937Sjkim    ACPI_PARSE_OBJECT       *Op,
65151937Sjkim    UINT32                  Level,
66151937Sjkim    void                    *Context);
67151937Sjkim
68151937Sjkimstatic ACPI_STATUS
69151937SjkimOpcAmlCheckForConstant (
70151937Sjkim    ACPI_PARSE_OBJECT       *Op,
71151937Sjkim    UINT32                  Level,
72151937Sjkim    void                    *Context);
73151937Sjkim
74239340Sjkimstatic void
75239340SjkimOpcUpdateIntegerNode (
76239340Sjkim    ACPI_PARSE_OBJECT       *Op,
77239340Sjkim    UINT64                  Value);
78151937Sjkim
79281687Sjkimstatic ACPI_STATUS
80281687SjkimTrTransformToStoreOp (
81281687Sjkim    ACPI_PARSE_OBJECT       *Op,
82281687Sjkim    ACPI_WALK_STATE         *WalkState);
83239340Sjkim
84281687Sjkimstatic ACPI_STATUS
85281687SjkimTrSimpleConstantReduction (
86281687Sjkim    ACPI_PARSE_OBJECT       *Op,
87281687Sjkim    ACPI_WALK_STATE         *WalkState);
88281687Sjkim
89281687Sjkimstatic void
90281687SjkimTrInstallReducedConstant (
91281687Sjkim    ACPI_PARSE_OBJECT       *Op,
92281687Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc);
93281687Sjkim
94281687Sjkim
95118611Snjl/*******************************************************************************
96118611Snjl *
97281687Sjkim * FUNCTION:    OpcAmlConstantWalk
98118611Snjl *
99118611Snjl * PARAMETERS:  ASL_WALK_CALLBACK
100118611Snjl *
101118611Snjl * RETURN:      Status
102118611Snjl *
103306536Sjkim * DESCRIPTION: Reduce an Op and its subtree to a constant if possible.
104306536Sjkim *              Called during ascent of the parse tree.
105118611Snjl *
106118611Snjl ******************************************************************************/
107118611Snjl
108281687SjkimACPI_STATUS
109281687SjkimOpcAmlConstantWalk (
110118611Snjl    ACPI_PARSE_OBJECT       *Op,
111118611Snjl    UINT32                  Level,
112118611Snjl    void                    *Context)
113118611Snjl{
114281687Sjkim    ACPI_WALK_STATE         *WalkState;
115281687Sjkim    ACPI_STATUS             Status = AE_OK;
116118611Snjl
117118611Snjl
118281687Sjkim    if (Op->Asl.CompileFlags == 0)
119281687Sjkim    {
120281687Sjkim        return (AE_OK);
121281687Sjkim    }
122118611Snjl
123281687Sjkim    /*
124281687Sjkim     * Only interested in subtrees that could possibly contain
125281687Sjkim     * expressions that can be evaluated at this time
126281687Sjkim     */
127281687Sjkim    if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) ||
128281687Sjkim          (Op->Asl.CompileFlags & NODE_IS_TARGET))
129118611Snjl    {
130281687Sjkim        return (AE_OK);
131118611Snjl    }
132118611Snjl
133281687Sjkim    /* Create a new walk state */
134118611Snjl
135281687Sjkim    WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
136281687Sjkim    if (!WalkState)
137118611Snjl    {
138281687Sjkim        return (AE_NO_MEMORY);
139118611Snjl    }
140118611Snjl
141281687Sjkim    WalkState->NextOp = NULL;
142281687Sjkim    WalkState->Params = NULL;
143118611Snjl
144281687Sjkim    /*
145281687Sjkim     * Examine the entire subtree -- all nodes must be constants
146281687Sjkim     * or type 3/4/5 opcodes
147281687Sjkim     */
148281687Sjkim    Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
149281687Sjkim        OpcAmlCheckForConstant, NULL, WalkState);
150118611Snjl
151281687Sjkim    /*
152281687Sjkim     * Did we find an entire subtree that contains all constants
153281687Sjkim     * and type 3/4/5 opcodes?
154281687Sjkim     */
155281687Sjkim    switch (Status)
156281687Sjkim    {
157281687Sjkim    case AE_OK:
158118611Snjl
159281687Sjkim        /* Simple case, like Add(3,4) -> 7 */
160118611Snjl
161281687Sjkim        Status = TrSimpleConstantReduction (Op, WalkState);
162281687Sjkim        break;
163118611Snjl
164281687Sjkim    case AE_CTRL_RETURN_VALUE:
165118611Snjl
166281687Sjkim        /* More complex case, like Add(3,4,Local0) -> Store(7,Local0) */
167118611Snjl
168281687Sjkim        Status = TrTransformToStoreOp (Op, WalkState);
169281687Sjkim        break;
170281687Sjkim
171281687Sjkim    case AE_TYPE:
172281687Sjkim
173281687Sjkim        AcpiDsDeleteWalkState (WalkState);
174281687Sjkim        return (AE_OK);
175281687Sjkim
176281687Sjkim    default:
177281687Sjkim        AcpiDsDeleteWalkState (WalkState);
178281687Sjkim        break;
179118611Snjl    }
180118611Snjl
181118611Snjl    if (ACPI_FAILURE (Status))
182118611Snjl    {
183281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT, "Cannot resolve, %s\n",
184281687Sjkim            AcpiFormatException (Status));
185281687Sjkim
186281687Sjkim        /* We could not resolve the subtree for some reason */
187281687Sjkim
188281687Sjkim        AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
189281687Sjkim            (char *) AcpiFormatException (Status));
190281687Sjkim
191281687Sjkim        /* Set the subtree value to ZERO anyway. Eliminates further errors */
192281687Sjkim
193281687Sjkim        OpcUpdateIntegerNode (Op, 0);
194118611Snjl    }
195118611Snjl
196306536Sjkim    return (AE_OK);
197118611Snjl}
198118611Snjl
199118611Snjl
200118611Snjl/*******************************************************************************
201118611Snjl *
202118611Snjl * FUNCTION:    OpcAmlCheckForConstant
203118611Snjl *
204118611Snjl * PARAMETERS:  ASL_WALK_CALLBACK
205118611Snjl *
206118611Snjl * RETURN:      Status
207118611Snjl *
208306536Sjkim * DESCRIPTION: Check one Op for a reducible type 3/4/5 AML opcode.
209306536Sjkim *              This is performed via an upward walk of the parse subtree.
210118611Snjl *
211118611Snjl ******************************************************************************/
212118611Snjl
213151937Sjkimstatic ACPI_STATUS
214118611SnjlOpcAmlCheckForConstant (
215118611Snjl    ACPI_PARSE_OBJECT       *Op,
216118611Snjl    UINT32                  Level,
217118611Snjl    void                    *Context)
218118611Snjl{
219118611Snjl    ACPI_WALK_STATE         *WalkState = Context;
220281687Sjkim    ACPI_STATUS             Status = AE_OK;
221306536Sjkim    ACPI_PARSE_OBJECT       *NextOp;
222306536Sjkim    const ACPI_OPCODE_INFO  *OpInfo;
223118611Snjl
224118611Snjl
225118611Snjl    WalkState->Op = Op;
226118611Snjl    WalkState->Opcode = Op->Common.AmlOpcode;
227118611Snjl    WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
228118611Snjl
229118611Snjl    DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ",
230281687Sjkim        Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
231118611Snjl
232240716Sjkim    /*
233240716Sjkim     * These opcodes do not appear in the OpcodeInfo table, but
234240716Sjkim     * they represent constants, so abort the constant walk now.
235240716Sjkim     */
236240716Sjkim    if ((WalkState->Opcode == AML_RAW_DATA_BYTE) ||
237240716Sjkim        (WalkState->Opcode == AML_RAW_DATA_WORD) ||
238240716Sjkim        (WalkState->Opcode == AML_RAW_DATA_DWORD) ||
239240716Sjkim        (WalkState->Opcode == AML_RAW_DATA_QWORD))
240240716Sjkim    {
241281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT, "RAW DATA");
242281687Sjkim        Status = AE_TYPE;
243281687Sjkim        goto CleanupAndExit;
244240716Sjkim    }
245240716Sjkim
246306536Sjkim    /*
247306536Sjkim     * Search upwards for a possible Name() operator. This is done
248306536Sjkim     * because a type 3/4/5 opcode within a Name() expression
249306536Sjkim     * MUST be reduced to a simple constant.
250306536Sjkim     */
251306536Sjkim    NextOp = Op->Asl.Parent;
252306536Sjkim    while (NextOp)
253306536Sjkim    {
254306536Sjkim        /* Finished if we find a Name() opcode */
255306536Sjkim
256306536Sjkim        if (NextOp->Asl.AmlOpcode == AML_NAME_OP)
257306536Sjkim        {
258306536Sjkim            break;
259306536Sjkim        }
260306536Sjkim
261306536Sjkim        /*
262306536Sjkim         * Any "deferred" opcodes contain one or more TermArg parameters,
263306536Sjkim         * and thus are not required to be folded to constants at compile
264306536Sjkim         * time. This affects things like Buffer() and Package() objects.
265306536Sjkim         * We just ignore them here. However, any sub-expressions can and
266306536Sjkim         * will still be typechecked. Note: These are called the
267306536Sjkim         * "deferred" opcodes in the AML interpreter.
268306536Sjkim         */
269306536Sjkim        OpInfo = AcpiPsGetOpcodeInfo (NextOp->Common.AmlOpcode);
270306536Sjkim        if (OpInfo->Flags & AML_DEFER)
271306536Sjkim        {
272306536Sjkim            NextOp = NULL;
273306536Sjkim            break;
274306536Sjkim        }
275306536Sjkim
276306536Sjkim        NextOp = NextOp->Asl.Parent;
277306536Sjkim    }
278306536Sjkim
279281687Sjkim    /* Type 3/4/5 opcodes have the AML_CONSTANT flag set */
280281687Sjkim
281118611Snjl    if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
282118611Snjl    {
283306536Sjkim        /*
284306536Sjkim         * From the ACPI specification:
285306536Sjkim         *
286306536Sjkim         * "The Type 3/4/5 opcodes return a value and can be used in an
287306536Sjkim         * expression that evaluates to a constant. These opcodes may be
288306536Sjkim         * evaluated at ASL compile-time. To ensure that these opcodes
289306536Sjkim         * will evaluate to a constant, the following rules apply: The
290306536Sjkim         * term cannot have a destination (target) operand, and must have
291306536Sjkim         * either a Type3Opcode, Type4Opcode, Type5Opcode, ConstExprTerm,
292306536Sjkim         * Integer, BufferTerm, Package, or String for all arguments."
293306536Sjkim         */
294118611Snjl
295306536Sjkim        /*
296306536Sjkim         * The value (second) operand for the Name() operator MUST
297306536Sjkim         * reduce to a single constant, as per the ACPI specification
298306536Sjkim         * (the operand is a DataObject). This also implies that there
299306536Sjkim         * can be no target operand. Name() is the only ASL operator
300306536Sjkim         * with a "DataObject" as an operand and is thus special-
301306536Sjkim         * cased here.
302306536Sjkim         */
303306536Sjkim        if (NextOp) /* Inspect a Name() operator */
304306536Sjkim        {
305306536Sjkim            /* Error if there is a target operand */
306306536Sjkim
307306536Sjkim            if (Op->Asl.CompileFlags & NODE_IS_TARGET)
308306536Sjkim            {
309306536Sjkim                AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op, NULL);
310306536Sjkim                Status = AE_TYPE;
311306536Sjkim            }
312306536Sjkim
313306536Sjkim            /* Error if expression cannot be reduced (folded) */
314306536Sjkim
315306536Sjkim            if (!(NextOp->Asl.CompileFlags & NODE_COULD_NOT_REDUCE))
316306536Sjkim            {
317306536Sjkim                /* Ensure only one error message per statement */
318306536Sjkim
319306536Sjkim                NextOp->Asl.CompileFlags |= NODE_COULD_NOT_REDUCE;
320306536Sjkim                DbgPrint (ASL_PARSE_OUTPUT,
321306536Sjkim                    "**** Could not reduce operands for NAME opcode ****\n");
322306536Sjkim
323306536Sjkim                AslError (ASL_ERROR, ASL_MSG_CONSTANT_REQUIRED, Op,
324306536Sjkim                    "Constant is required for Name operator");
325306536Sjkim                Status = AE_TYPE;
326306536Sjkim            }
327306536Sjkim        }
328306536Sjkim
329306536Sjkim        if (ACPI_FAILURE (Status))
330306536Sjkim        {
331306536Sjkim            goto CleanupAndExit;
332306536Sjkim        }
333306536Sjkim
334306536Sjkim        /* This is not a 3/4/5 opcode, but maybe can convert to STORE */
335306536Sjkim
336118611Snjl        if (Op->Asl.CompileFlags & NODE_IS_TARGET)
337118611Snjl        {
338151937Sjkim            DbgPrint (ASL_PARSE_OUTPUT,
339281687Sjkim                "**** Valid Target, transform to Store ****\n");
340281687Sjkim            return (AE_CTRL_RETURN_VALUE);
341118611Snjl        }
342118611Snjl
343281687Sjkim        /* Expression cannot be reduced */
344118611Snjl
345281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
346306536Sjkim            "**** Not a Type 3/4/5 opcode or cannot reduce/fold (%s) ****\n",
347281687Sjkim             Op->Asl.ParseOpName);
348118611Snjl
349281687Sjkim        Status = AE_TYPE;
350281687Sjkim        goto CleanupAndExit;
351118611Snjl    }
352118611Snjl
353306536Sjkim    /*
354306536Sjkim     * TBD: Ignore buffer constants for now. The problem is that these
355306536Sjkim     * constants have been transformed into RAW_DATA at this point, from
356306536Sjkim     * the parse tree transform process which currently happens before
357306536Sjkim     * the constant folding process. We may need to defer this transform
358306536Sjkim     * for buffer until after the constant folding.
359306536Sjkim     */
360306536Sjkim    if (WalkState->Opcode == AML_BUFFER_OP)
361306536Sjkim    {
362306536Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
363306536Sjkim            "\nBuffer constant reduction is not supported yet\n");
364306536Sjkim
365306536Sjkim        if (NextOp) /* Found a Name() operator, error */
366306536Sjkim        {
367306536Sjkim            AslError (ASL_ERROR, ASL_MSG_UNSUPPORTED, Op,
368306536Sjkim                "Buffer expression cannot be reduced");
369306536Sjkim        }
370306536Sjkim
371306536Sjkim        Status = AE_TYPE;
372306536Sjkim        goto CleanupAndExit;
373306536Sjkim    }
374306536Sjkim
375118611Snjl    /* Debug output */
376118611Snjl
377118611Snjl    DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345");
378118611Snjl
379118611Snjl    if (Op->Asl.CompileFlags & NODE_IS_TARGET)
380118611Snjl    {
381281687Sjkim        if (Op->Asl.ParseOpcode == PARSEOP_ZERO)
382281687Sjkim        {
383281687Sjkim            DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " NULL TARGET");
384281687Sjkim        }
385281687Sjkim        else
386281687Sjkim        {
387281687Sjkim            DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " VALID TARGET");
388281687Sjkim        }
389118611Snjl    }
390306536Sjkim
391118611Snjl    if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
392118611Snjl    {
393281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " TERMARG");
394118611Snjl    }
395240716Sjkim
396281687SjkimCleanupAndExit:
397281687Sjkim
398281687Sjkim    /* Dump the node compile flags also */
399281687Sjkim
400281687Sjkim    TrPrintNodeCompileFlags (Op->Asl.CompileFlags);
401118611Snjl    DbgPrint (ASL_PARSE_OUTPUT, "\n");
402281687Sjkim    return (Status);
403118611Snjl}
404118611Snjl
405118611Snjl
406118611Snjl/*******************************************************************************
407118611Snjl *
408281687Sjkim * FUNCTION:    TrSimpleConstantReduction
409118611Snjl *
410281687Sjkim * PARAMETERS:  Op                  - Parent operator to be transformed
411281687Sjkim *              WalkState           - Current walk state
412118611Snjl *
413118611Snjl * RETURN:      Status
414118611Snjl *
415281687Sjkim * DESCRIPTION: Reduce an entire AML operation to a single constant. The
416281687Sjkim *              operation must not have a target operand.
417118611Snjl *
418281687Sjkim *              Add (32,64) --> 96
419281687Sjkim *
420118611Snjl ******************************************************************************/
421118611Snjl
422281687Sjkimstatic ACPI_STATUS
423281687SjkimTrSimpleConstantReduction (
424118611Snjl    ACPI_PARSE_OBJECT       *Op,
425281687Sjkim    ACPI_WALK_STATE         *WalkState)
426118611Snjl{
427118611Snjl    ACPI_PARSE_OBJECT       *RootOp;
428118611Snjl    ACPI_PARSE_OBJECT       *OriginalParentOp;
429281687Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc;
430281687Sjkim    ACPI_STATUS             Status;
431118611Snjl
432118611Snjl
433281687Sjkim    DbgPrint (ASL_PARSE_OUTPUT,
434281687Sjkim        "Simple subtree constant reduction, operator to constant\n");
435281687Sjkim
436281687Sjkim    /* Allocate a new temporary root for this subtree */
437281687Sjkim
438281687Sjkim    RootOp = TrAllocateNode (PARSEOP_INTEGER);
439281687Sjkim    if (!RootOp)
440118611Snjl    {
441281687Sjkim        return (AE_NO_MEMORY);
442118611Snjl    }
443118611Snjl
444281687Sjkim    RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
445151937Sjkim
446281687Sjkim    OriginalParentOp = Op->Common.Parent;
447281687Sjkim    Op->Common.Parent = RootOp;
448118611Snjl
449281687Sjkim    /* Hand off the subtree to the AML interpreter */
450118611Snjl
451281687Sjkim    WalkState->CallerReturnDesc = &ObjDesc;
452281687Sjkim
453281687Sjkim    Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
454281687Sjkim        OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
455281687Sjkim
456281687Sjkim    /* Restore original parse tree */
457281687Sjkim
458281687Sjkim    Op->Common.Parent = OriginalParentOp;
459281687Sjkim
460281687Sjkim    if (ACPI_FAILURE (Status))
461118611Snjl    {
462281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
463281687Sjkim            "Constant Subtree evaluation(1), %s\n",
464281687Sjkim            AcpiFormatException (Status));
465281687Sjkim        return (Status);
466118611Snjl    }
467118611Snjl
468281687Sjkim    /* Get the final result */
469118611Snjl
470281687Sjkim    Status = AcpiDsResultPop (&ObjDesc, WalkState);
471281687Sjkim    if (ACPI_FAILURE (Status))
472118611Snjl    {
473281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
474281687Sjkim            "Constant Subtree evaluation(2), %s\n",
475281687Sjkim            AcpiFormatException (Status));
476281687Sjkim        return (Status);
477118611Snjl    }
478118611Snjl
479306536Sjkim    /* Disconnect any existing children, install new constant */
480306536Sjkim
481306536Sjkim    Op->Asl.Child = NULL;
482281687Sjkim    TrInstallReducedConstant (Op, ObjDesc);
483118611Snjl
484281687Sjkim    UtSetParseOpName (Op);
485281687Sjkim    return (AE_OK);
486281687Sjkim}
487118611Snjl
488281687Sjkim
489281687Sjkim/*******************************************************************************
490281687Sjkim *
491281687Sjkim * FUNCTION:    TrTransformToStoreOp
492281687Sjkim *
493281687Sjkim * PARAMETERS:  Op                  - Parent operator to be transformed
494281687Sjkim *              WalkState           - Current walk state
495281687Sjkim *
496281687Sjkim * RETURN:      Status
497281687Sjkim *
498281687Sjkim * DESCRIPTION: Transforms a single AML operation with a constant and target
499281687Sjkim *              to a simple store operation:
500281687Sjkim *
501281687Sjkim *              Add (32,64,DATA) --> Store (96,DATA)
502281687Sjkim *
503281687Sjkim ******************************************************************************/
504281687Sjkim
505281687Sjkimstatic ACPI_STATUS
506281687SjkimTrTransformToStoreOp (
507281687Sjkim    ACPI_PARSE_OBJECT       *Op,
508281687Sjkim    ACPI_WALK_STATE         *WalkState)
509281687Sjkim{
510281687Sjkim    ACPI_PARSE_OBJECT       *OriginalTarget;
511281687Sjkim    ACPI_PARSE_OBJECT       *NewTarget;
512281687Sjkim    ACPI_PARSE_OBJECT       *Child1;
513281687Sjkim    ACPI_PARSE_OBJECT       *Child2;
514281687Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc;
515281687Sjkim    ACPI_PARSE_OBJECT       *NewParent;
516281687Sjkim    ACPI_PARSE_OBJECT       *OriginalParent;
517281687Sjkim    ACPI_STATUS             Status;
518281687Sjkim
519281687Sjkim
520281687Sjkim    /* Extract the operands */
521281687Sjkim
522281687Sjkim    Child1 = Op->Asl.Child;
523281687Sjkim    Child2 = Child1->Asl.Next;
524281687Sjkim
525118611Snjl    /*
526281687Sjkim     * Special case for DIVIDE -- it has two targets. The first
527281687Sjkim     * is for the remainder and if present, we will not attempt
528281687Sjkim     * to reduce the expression.
529118611Snjl     */
530281687Sjkim    if (Op->Asl.ParseOpcode == PARSEOP_DIVIDE)
531118611Snjl    {
532281687Sjkim        Child2 = Child2->Asl.Next;
533281687Sjkim        if (Child2->Asl.ParseOpcode != PARSEOP_ZERO)
534118611Snjl        {
535281687Sjkim            DbgPrint (ASL_PARSE_OUTPUT,
536281687Sjkim                "Cannot reduce DIVIDE - has two targets\n\n");
537118611Snjl            return (AE_OK);
538118611Snjl        }
539281687Sjkim    }
540118611Snjl
541306536Sjkim    DbgPrint (ASL_PARSE_OUTPUT,
542306536Sjkim        "Reduction/Transform to StoreOp: Store(%s, %s)\n",
543306536Sjkim        Child1->Asl.ParseOpName, Child2->Asl.ParseOpName);
544306536Sjkim
545281687Sjkim    /*
546281687Sjkim     * Create a NULL (zero) target so that we can use the
547281687Sjkim     * interpreter to evaluate the expression.
548281687Sjkim     */
549281687Sjkim    NewTarget = TrCreateNullTarget ();
550281687Sjkim    NewTarget->Common.AmlOpcode = AML_INT_NAMEPATH_OP;
551118611Snjl
552281687Sjkim    /* Handle one-operand cases (NOT, TOBCD, etc.) */
553281687Sjkim
554281687Sjkim    if (!Child2->Asl.Next)
555281687Sjkim    {
556281687Sjkim        Child2 = Child1;
557118611Snjl    }
558281687Sjkim
559281687Sjkim    /* Link in new NULL target as the last operand */
560281687Sjkim
561281687Sjkim    OriginalTarget = Child2->Asl.Next;
562281687Sjkim    Child2->Asl.Next = NewTarget;
563281687Sjkim    NewTarget->Asl.Parent = OriginalTarget->Asl.Parent;
564281687Sjkim
565281687Sjkim    NewParent = TrAllocateNode (PARSEOP_INTEGER);
566281687Sjkim    NewParent->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
567281687Sjkim
568281687Sjkim    OriginalParent = Op->Common.Parent;
569281687Sjkim    Op->Common.Parent = NewParent;
570281687Sjkim
571281687Sjkim    /* Hand off the subtree to the AML interpreter */
572281687Sjkim
573281687Sjkim    WalkState->CallerReturnDesc = &ObjDesc;
574281687Sjkim
575281687Sjkim    Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
576281687Sjkim        OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
577281687Sjkim    if (ACPI_FAILURE (Status))
578118611Snjl    {
579281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
580281687Sjkim            "Constant Subtree evaluation(3), %s\n",
581281687Sjkim            AcpiFormatException (Status));
582281687Sjkim        goto EvalError;
583281687Sjkim    }
584118611Snjl
585281687Sjkim    /* Get the final result */
586118611Snjl
587281687Sjkim    Status = AcpiDsResultPop (&ObjDesc, WalkState);
588281687Sjkim    if (ACPI_FAILURE (Status))
589281687Sjkim    {
590281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
591281687Sjkim            "Constant Subtree evaluation(4), %s\n",
592281687Sjkim            AcpiFormatException (Status));
593281687Sjkim        goto EvalError;
594281687Sjkim    }
595118611Snjl
596306536Sjkim    /* Truncate any subtree expressions, they have been evaluated */
597306536Sjkim
598306536Sjkim    Child1->Asl.Child = NULL;
599306536Sjkim
600281687Sjkim    /* Folded constant is in ObjDesc, store into Child1 */
601118611Snjl
602281687Sjkim    TrInstallReducedConstant (Child1, ObjDesc);
603118611Snjl
604281687Sjkim    /* Convert operator to STORE */
605151937Sjkim
606281687Sjkim    Op->Asl.ParseOpcode = PARSEOP_STORE;
607281687Sjkim    Op->Asl.AmlOpcode = AML_STORE_OP;
608281687Sjkim    UtSetParseOpName (Op);
609281687Sjkim    Op->Common.Parent = OriginalParent;
610118611Snjl
611281687Sjkim    /* First child is the folded constant */
612118611Snjl
613281687Sjkim    /* Second child will be the target */
614239340Sjkim
615281687Sjkim    Child1->Asl.Next = OriginalTarget;
616281687Sjkim    return (AE_OK);
617239340Sjkim
618118611Snjl
619281687SjkimEvalError:
620118611Snjl
621281687Sjkim    /* Restore original links */
622118611Snjl
623281687Sjkim    Op->Common.Parent = OriginalParent;
624281687Sjkim    Child2->Asl.Next = OriginalTarget;
625281687Sjkim    return (Status);
626281687Sjkim}
627118611Snjl
628118611Snjl
629281687Sjkim/*******************************************************************************
630281687Sjkim *
631281687Sjkim * FUNCTION:    TrInstallReducedConstant
632281687Sjkim *
633281687Sjkim * PARAMETERS:  Op                  - Parent operator to be transformed
634281687Sjkim *              ObjDesc             - Reduced constant to be installed
635281687Sjkim *
636281687Sjkim * RETURN:      None
637281687Sjkim *
638281687Sjkim * DESCRIPTION: Transform the original operator to a simple constant.
639281687Sjkim *              Handles Integers, Strings, and Buffers.
640281687Sjkim *
641281687Sjkim ******************************************************************************/
642118611Snjl
643281687Sjkimstatic void
644281687SjkimTrInstallReducedConstant (
645281687Sjkim    ACPI_PARSE_OBJECT       *Op,
646281687Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc)
647281687Sjkim{
648306536Sjkim    ACPI_PARSE_OBJECT       *LengthOp;
649306536Sjkim    ACPI_PARSE_OBJECT       *DataOp;
650118611Snjl
651118611Snjl
652281687Sjkim    TotalFolds++;
653281687Sjkim    AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
654281687Sjkim        Op->Asl.ParseOpName);
655118611Snjl
656281687Sjkim    /*
657281687Sjkim     * Because we know we executed type 3/4/5 opcodes above, we know that
658281687Sjkim     * the result must be either an Integer, String, or Buffer.
659281687Sjkim     */
660281687Sjkim    switch (ObjDesc->Common.Type)
661281687Sjkim    {
662281687Sjkim    case ACPI_TYPE_INTEGER:
663118611Snjl
664281687Sjkim        OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value);
665118611Snjl
666281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
667281687Sjkim            "Constant expression reduced to (%s) %8.8X%8.8X\n\n",
668281687Sjkim            Op->Asl.ParseOpName,
669281687Sjkim            ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
670281687Sjkim        break;
671118611Snjl
672281687Sjkim    case ACPI_TYPE_STRING:
673118611Snjl
674281687Sjkim        Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
675281687Sjkim        Op->Common.AmlOpcode = AML_STRING_OP;
676306536Sjkim        Op->Asl.AmlLength = strlen (ObjDesc->String.Pointer) + 1;
677281687Sjkim        Op->Common.Value.String = ObjDesc->String.Pointer;
678118611Snjl
679281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
680281687Sjkim            "Constant expression reduced to (STRING) %s\n\n",
681281687Sjkim            Op->Common.Value.String);
682281687Sjkim        break;
683118611Snjl
684281687Sjkim    case ACPI_TYPE_BUFFER:
685306536Sjkim        /*
686306536Sjkim         * Create a new parse subtree of the form:
687306536Sjkim         *
688306536Sjkim         * BUFFER (Buffer AML opcode)
689306536Sjkim         *    INTEGER (Buffer length in bytes)
690306536Sjkim         *    RAW_DATA (Buffer byte data)
691306536Sjkim         */
692281687Sjkim        Op->Asl.ParseOpcode = PARSEOP_BUFFER;
693281687Sjkim        Op->Common.AmlOpcode = AML_BUFFER_OP;
694281687Sjkim        Op->Asl.CompileFlags = NODE_AML_PACKAGE;
695281687Sjkim        UtSetParseOpName (Op);
696118611Snjl
697281687Sjkim        /* Child node is the buffer length */
698118611Snjl
699306536Sjkim        LengthOp = TrAllocateNode (PARSEOP_INTEGER);
700118611Snjl
701306536Sjkim        LengthOp->Asl.AmlOpcode = AML_DWORD_OP;
702306536Sjkim        LengthOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
703306536Sjkim        LengthOp->Asl.Parent = Op;
704306536Sjkim        (void) OpcSetOptimalIntegerSize (LengthOp);
705118611Snjl
706306536Sjkim        Op->Asl.Child = LengthOp;
707118611Snjl
708306536Sjkim        /* Next child is the raw buffer data */
709118611Snjl
710306536Sjkim        DataOp = TrAllocateNode (PARSEOP_RAW_DATA);
711306536Sjkim        DataOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
712306536Sjkim        DataOp->Asl.AmlLength = ObjDesc->Buffer.Length;
713306536Sjkim        DataOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer;
714306536Sjkim        DataOp->Asl.Parent = Op;
715118611Snjl
716306536Sjkim        LengthOp->Asl.Next = DataOp;
717118611Snjl
718281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
719281687Sjkim            "Constant expression reduced to (BUFFER) length %X\n\n",
720281687Sjkim            ObjDesc->Buffer.Length);
721281687Sjkim        break;
722281687Sjkim
723281687Sjkim    default:
724281687Sjkim        break;
725281687Sjkim    }
726118611Snjl}
727118611Snjl
728239340Sjkim
729239340Sjkim/*******************************************************************************
730239340Sjkim *
731239340Sjkim * FUNCTION:    OpcUpdateIntegerNode
732239340Sjkim *
733239340Sjkim * PARAMETERS:  Op                  - Current parse object
734281687Sjkim *              Value               - Value for the integer op
735239340Sjkim *
736239340Sjkim * RETURN:      None
737239340Sjkim *
738281687Sjkim * DESCRIPTION: Update node to the correct Integer type and value
739239340Sjkim *
740239340Sjkim ******************************************************************************/
741239340Sjkim
742239340Sjkimstatic void
743239340SjkimOpcUpdateIntegerNode (
744239340Sjkim    ACPI_PARSE_OBJECT       *Op,
745239340Sjkim    UINT64                  Value)
746239340Sjkim{
747239340Sjkim
748239340Sjkim    Op->Common.Value.Integer = Value;
749239340Sjkim
750239340Sjkim    /*
751239340Sjkim     * The AmlLength is used by the parser to indicate a constant,
752239340Sjkim     * (if non-zero). Length is either (1/2/4/8)
753239340Sjkim     */
754239340Sjkim    switch (Op->Asl.AmlLength)
755239340Sjkim    {
756239340Sjkim    case 1:
757250838Sjkim
758239340Sjkim        TrUpdateNode (PARSEOP_BYTECONST, Op);
759239340Sjkim        Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
760239340Sjkim        break;
761239340Sjkim
762239340Sjkim    case 2:
763250838Sjkim
764239340Sjkim        TrUpdateNode (PARSEOP_WORDCONST, Op);
765239340Sjkim        Op->Asl.AmlOpcode = AML_RAW_DATA_WORD;
766239340Sjkim        break;
767239340Sjkim
768239340Sjkim    case 4:
769250838Sjkim
770239340Sjkim        TrUpdateNode (PARSEOP_DWORDCONST, Op);
771239340Sjkim        Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD;
772239340Sjkim        break;
773239340Sjkim
774239340Sjkim    case 8:
775250838Sjkim
776239340Sjkim        TrUpdateNode (PARSEOP_QWORDCONST, Op);
777239340Sjkim        Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD;
778239340Sjkim        break;
779239340Sjkim
780239340Sjkim    case 0:
781239340Sjkim    default:
782250838Sjkim
783239340Sjkim        OpcSetOptimalIntegerSize (Op);
784239340Sjkim        TrUpdateNode (PARSEOP_INTEGER, Op);
785239340Sjkim        break;
786239340Sjkim    }
787239340Sjkim
788239340Sjkim    Op->Asl.AmlLength = 0;
789239340Sjkim}
790281687Sjkim
791281687Sjkim
792281687Sjkim/*******************************************************************************
793281687Sjkim *
794281687Sjkim * FUNCTION:    OpcAmlEvaluationWalk1
795281687Sjkim *
796281687Sjkim * PARAMETERS:  ASL_WALK_CALLBACK
797281687Sjkim *
798281687Sjkim * RETURN:      Status
799281687Sjkim *
800281687Sjkim * DESCRIPTION: Descending callback for AML execution of constant subtrees
801281687Sjkim *
802281687Sjkim ******************************************************************************/
803281687Sjkim
804281687Sjkimstatic ACPI_STATUS
805281687SjkimOpcAmlEvaluationWalk1 (
806281687Sjkim    ACPI_PARSE_OBJECT       *Op,
807281687Sjkim    UINT32                  Level,
808281687Sjkim    void                    *Context)
809281687Sjkim{
810281687Sjkim    ACPI_WALK_STATE         *WalkState = Context;
811281687Sjkim    ACPI_STATUS             Status;
812281687Sjkim    ACPI_PARSE_OBJECT       *OutOp;
813281687Sjkim
814281687Sjkim
815281687Sjkim    WalkState->Op = Op;
816281687Sjkim    WalkState->Opcode = Op->Common.AmlOpcode;
817281687Sjkim    WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
818281687Sjkim
819281687Sjkim    /* Copy child pointer to Arg for compatibility with Interpreter */
820281687Sjkim
821281687Sjkim    if (Op->Asl.Child)
822281687Sjkim    {
823281687Sjkim        Op->Common.Value.Arg = Op->Asl.Child;
824281687Sjkim    }
825281687Sjkim
826281687Sjkim    /* Call AML dispatcher */
827281687Sjkim
828281687Sjkim    Status = AcpiDsExecBeginOp (WalkState, &OutOp);
829281687Sjkim    if (ACPI_FAILURE (Status))
830281687Sjkim    {
831281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
832281687Sjkim            "%s Constant interpretation failed (1) - %s\n",
833281687Sjkim            Op->Asl.ParseOpName, AcpiFormatException (Status));
834281687Sjkim    }
835281687Sjkim
836281687Sjkim    return (Status);
837281687Sjkim}
838281687Sjkim
839281687Sjkim
840281687Sjkim/*******************************************************************************
841281687Sjkim *
842281687Sjkim * FUNCTION:    OpcAmlEvaluationWalk2
843281687Sjkim *
844281687Sjkim * PARAMETERS:  ASL_WALK_CALLBACK
845281687Sjkim *
846281687Sjkim * RETURN:      Status
847281687Sjkim *
848281687Sjkim * DESCRIPTION: Ascending callback for AML execution of constant subtrees
849281687Sjkim *
850281687Sjkim ******************************************************************************/
851281687Sjkim
852281687Sjkimstatic ACPI_STATUS
853281687SjkimOpcAmlEvaluationWalk2 (
854281687Sjkim    ACPI_PARSE_OBJECT       *Op,
855281687Sjkim    UINT32                  Level,
856281687Sjkim    void                    *Context)
857281687Sjkim{
858281687Sjkim    ACPI_WALK_STATE         *WalkState = Context;
859281687Sjkim    ACPI_STATUS             Status;
860281687Sjkim
861281687Sjkim
862281687Sjkim    WalkState->Op = Op;
863281687Sjkim    WalkState->Opcode = Op->Common.AmlOpcode;
864281687Sjkim    WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
865281687Sjkim
866281687Sjkim    /* Copy child pointer to Arg for compatibility with Interpreter */
867281687Sjkim
868281687Sjkim    if (Op->Asl.Child)
869281687Sjkim    {
870281687Sjkim        Op->Common.Value.Arg = Op->Asl.Child;
871281687Sjkim    }
872281687Sjkim
873281687Sjkim    /* Call AML dispatcher */
874281687Sjkim
875281687Sjkim    Status = AcpiDsExecEndOp (WalkState);
876281687Sjkim    if (ACPI_FAILURE (Status))
877281687Sjkim    {
878281687Sjkim        DbgPrint (ASL_PARSE_OUTPUT,
879281687Sjkim            "%s: Constant interpretation failed (2) - %s\n",
880281687Sjkim            Op->Asl.ParseOpName, AcpiFormatException (Status));
881281687Sjkim    }
882281687Sjkim
883281687Sjkim    return (Status);
884281687Sjkim}
885