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