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