1 /****************************************************************************** 2 * 3 * Module Name: aslfold - Constant folding 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2012, 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 <contrib/dev/acpica/compiler/aslcompiler.h> 46 #include "aslcompiler.y.h" 47 #include <contrib/dev/acpica/include/amlcode.h> 48 49 #include <contrib/dev/acpica/include/acdispat.h> 50 #include <contrib/dev/acpica/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 445 case ACPI_TYPE_STRING: 446 447 Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL; 448 Op->Common.AmlOpcode = AML_STRING_OP; 449 Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1; 450 Op->Common.Value.String = ObjDesc->String.Pointer; 451 452 DbgPrint (ASL_PARSE_OUTPUT, 453 "Constant expression reduced to (STRING) %s\n", 454 Op->Common.Value.String); 455 456 break; 457 458 459 case ACPI_TYPE_BUFFER: 460 461 Op->Asl.ParseOpcode = PARSEOP_BUFFER; 462 Op->Common.AmlOpcode = AML_BUFFER_OP; 463 Op->Asl.CompileFlags = NODE_AML_PACKAGE; 464 UtSetParseOpName (Op); 465 466 /* Child node is the buffer length */ 467 468 RootOp = TrAllocateNode (PARSEOP_INTEGER); 469 470 RootOp->Asl.AmlOpcode = AML_DWORD_OP; 471 RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length; 472 RootOp->Asl.Parent = Op; 473 474 (void) OpcSetOptimalIntegerSize (RootOp); 475 476 Op->Asl.Child = RootOp; 477 Op = RootOp; 478 UtSetParseOpName (Op); 479 480 /* Peer to the child is the raw buffer data */ 481 482 RootOp = TrAllocateNode (PARSEOP_RAW_DATA); 483 RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; 484 RootOp->Asl.AmlLength = ObjDesc->Buffer.Length; 485 RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer; 486 RootOp->Asl.Parent = Op->Asl.Parent; 487 488 Op->Asl.Next = RootOp; 489 Op = RootOp; 490 491 DbgPrint (ASL_PARSE_OUTPUT, 492 "Constant expression reduced to (BUFFER) length %X\n", 493 ObjDesc->Buffer.Length); 494 break; 495 496 497 default: 498 printf ("Unsupported return type: %s\n", 499 AcpiUtGetObjectTypeName (ObjDesc)); 500 break; 501 } 502 } 503 504 UtSetParseOpName (Op); 505 Op->Asl.Child = NULL; 506 507 AcpiDsDeleteWalkState (WalkState); 508 return (AE_CTRL_DEPTH); 509 } 510 511 512 /******************************************************************************* 513 * 514 * FUNCTION: OpcUpdateIntegerNode 515 * 516 * PARAMETERS: Op - Current parse object 517 * 518 * RETURN: None 519 * 520 * DESCRIPTION: Update node to the correct integer type. 521 * 522 ******************************************************************************/ 523 524 static void 525 OpcUpdateIntegerNode ( 526 ACPI_PARSE_OBJECT *Op, 527 UINT64 Value) 528 { 529 530 Op->Common.Value.Integer = Value; 531 532 /* 533 * The AmlLength is used by the parser to indicate a constant, 534 * (if non-zero). Length is either (1/2/4/8) 535 */ 536 switch (Op->Asl.AmlLength) 537 { 538 case 1: 539 TrUpdateNode (PARSEOP_BYTECONST, Op); 540 Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 541 break; 542 543 case 2: 544 TrUpdateNode (PARSEOP_WORDCONST, Op); 545 Op->Asl.AmlOpcode = AML_RAW_DATA_WORD; 546 break; 547 548 case 4: 549 TrUpdateNode (PARSEOP_DWORDCONST, Op); 550 Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD; 551 break; 552 553 case 8: 554 TrUpdateNode (PARSEOP_QWORDCONST, Op); 555 Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD; 556 break; 557 558 case 0: 559 default: 560 OpcSetOptimalIntegerSize (Op); 561 TrUpdateNode (PARSEOP_INTEGER, Op); 562 break; 563 } 564 565 Op->Asl.AmlLength = 0; 566 } 567