1 /******************************************************************************
3 * Module Name: aslfold - Constant folding
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2015, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
44 #include <contrib/dev/acpica/compiler/aslcompiler.h>
45 #include "aslcompiler.y.h"
46 #include <contrib/dev/acpica/include/amlcode.h>
48 #include <contrib/dev/acpica/include/acdispat.h>
49 #include <contrib/dev/acpica/include/acparser.h>
51 #define _COMPONENT ACPI_COMPILER
52 ACPI_MODULE_NAME ("aslfold")
54 /* Local prototypes */
57 OpcAmlEvaluationWalk1 (
58 ACPI_PARSE_OBJECT *Op,
63 OpcAmlEvaluationWalk2 (
64 ACPI_PARSE_OBJECT *Op,
69 OpcAmlCheckForConstant (
70 ACPI_PARSE_OBJECT *Op,
75 OpcUpdateIntegerNode (
76 ACPI_PARSE_OBJECT *Op,
80 /*******************************************************************************
82 * FUNCTION: OpcAmlEvaluationWalk1
84 * PARAMETERS: ASL_WALK_CALLBACK
88 * DESCRIPTION: Descending callback for AML execution of constant subtrees
90 ******************************************************************************/
93 OpcAmlEvaluationWalk1 (
94 ACPI_PARSE_OBJECT *Op,
98 ACPI_WALK_STATE *WalkState = Context;
100 ACPI_PARSE_OBJECT *OutOp;
104 WalkState->Opcode = Op->Common.AmlOpcode;
105 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
107 /* Copy child pointer to Arg for compatibility with Interpreter */
111 Op->Common.Value.Arg = Op->Asl.Child;
114 /* Call AML dispatcher */
116 Status = AcpiDsExecBeginOp (WalkState, &OutOp);
117 if (ACPI_FAILURE (Status))
119 AcpiOsPrintf ("Constant interpretation failed - %s\n",
120 AcpiFormatException (Status));
127 /*******************************************************************************
129 * FUNCTION: OpcAmlEvaluationWalk2
131 * PARAMETERS: ASL_WALK_CALLBACK
135 * DESCRIPTION: Ascending callback for AML execution of constant subtrees
137 ******************************************************************************/
140 OpcAmlEvaluationWalk2 (
141 ACPI_PARSE_OBJECT *Op,
145 ACPI_WALK_STATE *WalkState = Context;
150 WalkState->Opcode = Op->Common.AmlOpcode;
151 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
153 /* Copy child pointer to Arg for compatibility with Interpreter */
157 Op->Common.Value.Arg = Op->Asl.Child;
160 /* Call AML dispatcher */
162 Status = AcpiDsExecEndOp (WalkState);
163 if (ACPI_FAILURE (Status))
165 AcpiOsPrintf ("Constant interpretation failed - %s\n",
166 AcpiFormatException (Status));
173 /*******************************************************************************
175 * FUNCTION: OpcAmlCheckForConstant
177 * PARAMETERS: ASL_WALK_CALLBACK
181 * DESCRIPTION: Check one Op for a type 3/4/5 AML opcode
183 ******************************************************************************/
186 OpcAmlCheckForConstant (
187 ACPI_PARSE_OBJECT *Op,
191 ACPI_WALK_STATE *WalkState = Context;
195 WalkState->Opcode = Op->Common.AmlOpcode;
196 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
198 DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ",
199 Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
202 * These opcodes do not appear in the OpcodeInfo table, but
203 * they represent constants, so abort the constant walk now.
205 if ((WalkState->Opcode == AML_RAW_DATA_BYTE) ||
206 (WalkState->Opcode == AML_RAW_DATA_WORD) ||
207 (WalkState->Opcode == AML_RAW_DATA_DWORD) ||
208 (WalkState->Opcode == AML_RAW_DATA_QWORD))
210 WalkState->WalkType = ACPI_WALK_CONST_OPTIONAL;
214 if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
216 /* The opcode is not a Type 3/4/5 opcode */
218 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
220 DbgPrint (ASL_PARSE_OUTPUT,
221 "**** Valid Target, cannot reduce ****\n");
225 DbgPrint (ASL_PARSE_OUTPUT,
226 "**** Not a Type 3/4/5 opcode ****\n");
229 if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
232 * We are looking at at normal expression to see if it can be
233 * reduced. It can't. No error
239 * This is an expression that MUST reduce to a constant, and it
240 * can't be reduced. This is an error
242 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
244 AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op,
245 Op->Asl.ParseOpName);
249 AslError (ASL_ERROR, ASL_MSG_INVALID_CONSTANT_OP, Op,
250 Op->Asl.ParseOpName);
258 DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345");
260 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
262 DbgPrint (ASL_PARSE_OUTPUT, " TARGET");
264 if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
266 DbgPrint (ASL_PARSE_OUTPUT, " TERMARG");
269 DbgPrint (ASL_PARSE_OUTPUT, "\n");
274 /*******************************************************************************
276 * FUNCTION: OpcAmlConstantWalk
278 * PARAMETERS: ASL_WALK_CALLBACK
282 * DESCRIPTION: Reduce an Op and its subtree to a constant if possible
284 ******************************************************************************/
288 ACPI_PARSE_OBJECT *Op,
292 ACPI_WALK_STATE *WalkState;
293 ACPI_STATUS Status = AE_OK;
294 ACPI_OPERAND_OBJECT *ObjDesc;
295 ACPI_PARSE_OBJECT *RootOp;
296 ACPI_PARSE_OBJECT *OriginalParentOp;
301 * Only interested in subtrees that could possibly contain
302 * expressions that can be evaluated at this time
304 if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) ||
305 (Op->Asl.CompileFlags & NODE_IS_TARGET))
310 /* Set the walk type based on the reduction used for this op */
312 if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
314 /* Op is a TermArg, constant folding is merely optional */
316 if (!Gbl_FoldConstants)
318 return (AE_CTRL_DEPTH);
321 WalkType = ACPI_WALK_CONST_OPTIONAL;
325 /* Op is a DataObject, the expression MUST reduced to a constant */
327 WalkType = ACPI_WALK_CONST_REQUIRED;
330 /* Create a new walk state */
332 WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
335 return (AE_NO_MEMORY);
338 WalkState->NextOp = NULL;
339 WalkState->Params = NULL;
340 WalkState->WalkType = WalkType;
341 WalkState->CallerReturnDesc = &ObjDesc;
344 * Examine the entire subtree -- all nodes must be constants
345 * or type 3/4/5 opcodes
347 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
348 OpcAmlCheckForConstant, NULL, WalkState);
351 * Did we find an entire subtree that contains all constants and type 3/4/5
352 * opcodes? (Only AE_OK or AE_TYPE returned from above)
354 if (Status == AE_TYPE)
356 /* Subtree cannot be reduced to a constant */
358 if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
360 AcpiDsDeleteWalkState (WalkState);
364 /* Don't descend any further, and use a default "constant" value */
366 Status = AE_CTRL_DEPTH;
370 /* Subtree can be reduced */
372 /* Allocate a new temporary root for this subtree */
374 RootOp = TrAllocateNode (PARSEOP_INTEGER);
377 return (AE_NO_MEMORY);
380 RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
382 OriginalParentOp = Op->Common.Parent;
383 Op->Common.Parent = RootOp;
385 /* Hand off the subtree to the AML interpreter */
387 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
388 OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
389 Op->Common.Parent = OriginalParentOp;
391 /* TBD: we really *should* release the RootOp node */
393 if (ACPI_SUCCESS (Status))
397 /* Get the final result */
399 Status = AcpiDsResultPop (&ObjDesc, WalkState);
402 /* Check for error from the ACPICA core */
404 if (ACPI_FAILURE (Status))
406 AslCoreSubsystemError (Op, Status,
407 "Failure during constant evaluation", FALSE);
411 if (ACPI_FAILURE (Status))
413 /* We could not resolve the subtree for some reason */
415 AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
416 Op->Asl.ParseOpName);
418 /* Set the subtree value to ZERO anyway. Eliminates further errors */
420 OpcUpdateIntegerNode (Op, 0);
424 AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
425 Op->Asl.ParseOpName);
428 * Because we know we executed type 3/4/5 opcodes above, we know that
429 * the result must be either an Integer, String, or Buffer.
431 switch (ObjDesc->Common.Type)
433 case ACPI_TYPE_INTEGER:
435 OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value);
437 DbgPrint (ASL_PARSE_OUTPUT,
438 "Constant expression reduced to (%s) %8.8X%8.8X\n",
440 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
443 case ACPI_TYPE_STRING:
445 Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
446 Op->Common.AmlOpcode = AML_STRING_OP;
447 Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1;
448 Op->Common.Value.String = ObjDesc->String.Pointer;
450 DbgPrint (ASL_PARSE_OUTPUT,
451 "Constant expression reduced to (STRING) %s\n",
452 Op->Common.Value.String);
456 case ACPI_TYPE_BUFFER:
458 Op->Asl.ParseOpcode = PARSEOP_BUFFER;
459 Op->Common.AmlOpcode = AML_BUFFER_OP;
460 Op->Asl.CompileFlags = NODE_AML_PACKAGE;
461 UtSetParseOpName (Op);
463 /* Child node is the buffer length */
465 RootOp = TrAllocateNode (PARSEOP_INTEGER);
467 RootOp->Asl.AmlOpcode = AML_DWORD_OP;
468 RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
469 RootOp->Asl.Parent = Op;
471 (void) OpcSetOptimalIntegerSize (RootOp);
473 Op->Asl.Child = RootOp;
475 UtSetParseOpName (Op);
477 /* Peer to the child is the raw buffer data */
479 RootOp = TrAllocateNode (PARSEOP_RAW_DATA);
480 RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
481 RootOp->Asl.AmlLength = ObjDesc->Buffer.Length;
482 RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer;
483 RootOp->Asl.Parent = Op->Asl.Parent;
485 Op->Asl.Next = RootOp;
488 DbgPrint (ASL_PARSE_OUTPUT,
489 "Constant expression reduced to (BUFFER) length %X\n",
490 ObjDesc->Buffer.Length);
495 printf ("Unsupported return type: %s\n",
496 AcpiUtGetObjectTypeName (ObjDesc));
501 UtSetParseOpName (Op);
502 Op->Asl.Child = NULL;
504 AcpiDsDeleteWalkState (WalkState);
505 return (AE_CTRL_DEPTH);
509 /*******************************************************************************
511 * FUNCTION: OpcUpdateIntegerNode
513 * PARAMETERS: Op - Current parse object
517 * DESCRIPTION: Update node to the correct integer type.
519 ******************************************************************************/
522 OpcUpdateIntegerNode (
523 ACPI_PARSE_OBJECT *Op,
527 Op->Common.Value.Integer = Value;
530 * The AmlLength is used by the parser to indicate a constant,
531 * (if non-zero). Length is either (1/2/4/8)
533 switch (Op->Asl.AmlLength)
537 TrUpdateNode (PARSEOP_BYTECONST, Op);
538 Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
543 TrUpdateNode (PARSEOP_WORDCONST, Op);
544 Op->Asl.AmlOpcode = AML_RAW_DATA_WORD;
549 TrUpdateNode (PARSEOP_DWORDCONST, Op);
550 Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD;
555 TrUpdateNode (PARSEOP_QWORDCONST, Op);
556 Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD;
562 OpcSetOptimalIntegerSize (Op);
563 TrUpdateNode (PARSEOP_INTEGER, Op);
567 Op->Asl.AmlLength = 0;