Home | History | Annotate | Line # | Download | only in compiler
aslfold.c revision 1.1.1.3
      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 "aslcompiler.h"
     46 #include "aslcompiler.y.h"
     47 #include "amlcode.h"
     48 
     49 #include "acdispat.h"
     50 #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         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 
    522 static void
    523 OpcUpdateIntegerNode (
    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