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