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