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 }