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 TrTransformToStoreOp (
81 ACPI_PARSE_OBJECT *Op,
82 ACPI_WALK_STATE *WalkState);
85 TrSimpleConstantReduction (
86 ACPI_PARSE_OBJECT *Op,
87 ACPI_WALK_STATE *WalkState);
90 TrInstallReducedConstant (
91 ACPI_PARSE_OBJECT *Op,
92 ACPI_OPERAND_OBJECT *ObjDesc);
95 /*******************************************************************************
97 * FUNCTION: OpcAmlConstantWalk
99 * PARAMETERS: ASL_WALK_CALLBACK
103 * DESCRIPTION: Reduce an Op and its subtree to a constant if possible
105 ******************************************************************************/
109 ACPI_PARSE_OBJECT *Op,
113 ACPI_WALK_STATE *WalkState;
114 ACPI_STATUS Status = AE_OK;
117 if (Op->Asl.CompileFlags == 0)
123 * Only interested in subtrees that could possibly contain
124 * expressions that can be evaluated at this time
126 if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) ||
127 (Op->Asl.CompileFlags & NODE_IS_TARGET))
132 /* Create a new walk state */
134 WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
137 return (AE_NO_MEMORY);
140 WalkState->NextOp = NULL;
141 WalkState->Params = NULL;
144 * Examine the entire subtree -- all nodes must be constants
145 * or type 3/4/5 opcodes
147 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
148 OpcAmlCheckForConstant, NULL, WalkState);
151 * Did we find an entire subtree that contains all constants
152 * and type 3/4/5 opcodes?
158 /* Simple case, like Add(3,4) -> 7 */
160 Status = TrSimpleConstantReduction (Op, WalkState);
163 case AE_CTRL_RETURN_VALUE:
165 /* More complex case, like Add(3,4,Local0) -> Store(7,Local0) */
167 Status = TrTransformToStoreOp (Op, WalkState);
172 AcpiDsDeleteWalkState (WalkState);
176 AcpiDsDeleteWalkState (WalkState);
180 if (ACPI_FAILURE (Status))
182 DbgPrint (ASL_PARSE_OUTPUT, "Cannot resolve, %s\n",
183 AcpiFormatException (Status));
185 /* We could not resolve the subtree for some reason */
187 AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
188 (char *) AcpiFormatException (Status));
190 /* Set the subtree value to ZERO anyway. Eliminates further errors */
192 OpcUpdateIntegerNode (Op, 0);
195 /* Abort the walk of this subtree, we are done with it */
197 return (AE_CTRL_DEPTH);
201 /*******************************************************************************
203 * FUNCTION: OpcAmlCheckForConstant
205 * PARAMETERS: ASL_WALK_CALLBACK
209 * DESCRIPTION: Check one Op for a type 3/4/5 AML opcode
211 ******************************************************************************/
214 OpcAmlCheckForConstant (
215 ACPI_PARSE_OBJECT *Op,
219 ACPI_WALK_STATE *WalkState = Context;
220 ACPI_STATUS Status = AE_OK;
224 WalkState->Opcode = Op->Common.AmlOpcode;
225 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
227 DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ",
228 Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
231 * TBD: Ignore buffer constants for now. The problem is that these
232 * constants have been transformed into RAW_DATA at this point, from
233 * the parse tree transform process which currently happens before
234 * the constant folding process. We may need to defer this transform
235 * for buffer until after the constant folding.
237 if (WalkState->Opcode == AML_BUFFER_OP)
244 * These opcodes do not appear in the OpcodeInfo table, but
245 * they represent constants, so abort the constant walk now.
247 if ((WalkState->Opcode == AML_RAW_DATA_BYTE) ||
248 (WalkState->Opcode == AML_RAW_DATA_WORD) ||
249 (WalkState->Opcode == AML_RAW_DATA_DWORD) ||
250 (WalkState->Opcode == AML_RAW_DATA_QWORD))
252 DbgPrint (ASL_PARSE_OUTPUT, "RAW DATA");
257 /* Type 3/4/5 opcodes have the AML_CONSTANT flag set */
259 if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
261 /* Not 3/4/5 opcode, but maybe can convert to STORE */
263 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
265 DbgPrint (ASL_PARSE_OUTPUT,
266 "**** Valid Target, transform to Store ****\n");
267 return (AE_CTRL_RETURN_VALUE);
270 /* Expression cannot be reduced */
272 DbgPrint (ASL_PARSE_OUTPUT,
273 "**** Not a Type 3/4/5 opcode (%s) ****",
274 Op->Asl.ParseOpName);
282 DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345");
284 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
286 if (Op->Asl.ParseOpcode == PARSEOP_ZERO)
288 DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " NULL TARGET");
292 DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " VALID TARGET");
295 if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
297 DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " TERMARG");
302 /* Dump the node compile flags also */
304 TrPrintNodeCompileFlags (Op->Asl.CompileFlags);
305 DbgPrint (ASL_PARSE_OUTPUT, "\n");
310 /*******************************************************************************
312 * FUNCTION: TrSimpleConstantReduction
314 * PARAMETERS: Op - Parent operator to be transformed
315 * WalkState - Current walk state
319 * DESCRIPTION: Reduce an entire AML operation to a single constant. The
320 * operation must not have a target operand.
324 ******************************************************************************/
327 TrSimpleConstantReduction (
328 ACPI_PARSE_OBJECT *Op,
329 ACPI_WALK_STATE *WalkState)
331 ACPI_PARSE_OBJECT *RootOp;
332 ACPI_PARSE_OBJECT *OriginalParentOp;
333 ACPI_OPERAND_OBJECT *ObjDesc;
337 DbgPrint (ASL_PARSE_OUTPUT,
338 "Simple subtree constant reduction, operator to constant\n");
340 /* Allocate a new temporary root for this subtree */
342 RootOp = TrAllocateNode (PARSEOP_INTEGER);
345 return (AE_NO_MEMORY);
348 RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
350 OriginalParentOp = Op->Common.Parent;
351 Op->Common.Parent = RootOp;
353 /* Hand off the subtree to the AML interpreter */
355 WalkState->CallerReturnDesc = &ObjDesc;
357 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
358 OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
360 /* Restore original parse tree */
362 Op->Common.Parent = OriginalParentOp;
364 if (ACPI_FAILURE (Status))
366 DbgPrint (ASL_PARSE_OUTPUT,
367 "Constant Subtree evaluation(1), %s\n",
368 AcpiFormatException (Status));
372 /* Get the final result */
374 Status = AcpiDsResultPop (&ObjDesc, WalkState);
375 if (ACPI_FAILURE (Status))
377 DbgPrint (ASL_PARSE_OUTPUT,
378 "Constant Subtree evaluation(2), %s\n",
379 AcpiFormatException (Status));
383 TrInstallReducedConstant (Op, ObjDesc);
385 UtSetParseOpName (Op);
386 Op->Asl.Child = NULL;
391 /*******************************************************************************
393 * FUNCTION: TrTransformToStoreOp
395 * PARAMETERS: Op - Parent operator to be transformed
396 * WalkState - Current walk state
400 * DESCRIPTION: Transforms a single AML operation with a constant and target
401 * to a simple store operation:
403 * Add (32,64,DATA) --> Store (96,DATA)
405 ******************************************************************************/
408 TrTransformToStoreOp (
409 ACPI_PARSE_OBJECT *Op,
410 ACPI_WALK_STATE *WalkState)
412 ACPI_PARSE_OBJECT *OriginalTarget;
413 ACPI_PARSE_OBJECT *NewTarget;
414 ACPI_PARSE_OBJECT *Child1;
415 ACPI_PARSE_OBJECT *Child2;
416 ACPI_OPERAND_OBJECT *ObjDesc;
417 ACPI_PARSE_OBJECT *NewParent;
418 ACPI_PARSE_OBJECT *OriginalParent;
422 DbgPrint (ASL_PARSE_OUTPUT,
423 "Reduction/Transform to StoreOp: Store(Constant, Target)\n");
425 /* Extract the operands */
427 Child1 = Op->Asl.Child;
428 Child2 = Child1->Asl.Next;
431 * Special case for DIVIDE -- it has two targets. The first
432 * is for the remainder and if present, we will not attempt
433 * to reduce the expression.
435 if (Op->Asl.ParseOpcode == PARSEOP_DIVIDE)
437 Child2 = Child2->Asl.Next;
438 if (Child2->Asl.ParseOpcode != PARSEOP_ZERO)
440 DbgPrint (ASL_PARSE_OUTPUT,
441 "Cannot reduce DIVIDE - has two targets\n\n");
447 * Create a NULL (zero) target so that we can use the
448 * interpreter to evaluate the expression.
450 NewTarget = TrCreateNullTarget ();
451 NewTarget->Common.AmlOpcode = AML_INT_NAMEPATH_OP;
453 /* Handle one-operand cases (NOT, TOBCD, etc.) */
455 if (!Child2->Asl.Next)
460 /* Link in new NULL target as the last operand */
462 OriginalTarget = Child2->Asl.Next;
463 Child2->Asl.Next = NewTarget;
464 NewTarget->Asl.Parent = OriginalTarget->Asl.Parent;
466 NewParent = TrAllocateNode (PARSEOP_INTEGER);
467 NewParent->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
469 OriginalParent = Op->Common.Parent;
470 Op->Common.Parent = NewParent;
472 /* Hand off the subtree to the AML interpreter */
474 WalkState->CallerReturnDesc = &ObjDesc;
476 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
477 OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
478 if (ACPI_FAILURE (Status))
480 DbgPrint (ASL_PARSE_OUTPUT,
481 "Constant Subtree evaluation(3), %s\n",
482 AcpiFormatException (Status));
486 /* Get the final result */
488 Status = AcpiDsResultPop (&ObjDesc, WalkState);
489 if (ACPI_FAILURE (Status))
491 DbgPrint (ASL_PARSE_OUTPUT,
492 "Constant Subtree evaluation(4), %s\n",
493 AcpiFormatException (Status));
497 /* Folded constant is in ObjDesc, store into Child1 */
499 TrInstallReducedConstant (Child1, ObjDesc);
501 /* Convert operator to STORE */
503 Op->Asl.ParseOpcode = PARSEOP_STORE;
504 Op->Asl.AmlOpcode = AML_STORE_OP;
505 UtSetParseOpName (Op);
506 Op->Common.Parent = OriginalParent;
508 /* Truncate any subtree expressions, they have been evaluated */
510 Child1->Asl.Child = NULL;
511 Child2->Asl.Child = NULL;
513 /* First child is the folded constant */
515 /* Second child will be the target */
517 Child1->Asl.Next = OriginalTarget;
523 /* Restore original links */
525 Op->Common.Parent = OriginalParent;
526 Child2->Asl.Next = OriginalTarget;
531 /*******************************************************************************
533 * FUNCTION: TrInstallReducedConstant
535 * PARAMETERS: Op - Parent operator to be transformed
536 * ObjDesc - Reduced constant to be installed
540 * DESCRIPTION: Transform the original operator to a simple constant.
541 * Handles Integers, Strings, and Buffers.
543 ******************************************************************************/
546 TrInstallReducedConstant (
547 ACPI_PARSE_OBJECT *Op,
548 ACPI_OPERAND_OBJECT *ObjDesc)
550 ACPI_PARSE_OBJECT *RootOp;
554 AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
555 Op->Asl.ParseOpName);
558 * Because we know we executed type 3/4/5 opcodes above, we know that
559 * the result must be either an Integer, String, or Buffer.
561 switch (ObjDesc->Common.Type)
563 case ACPI_TYPE_INTEGER:
565 OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value);
567 DbgPrint (ASL_PARSE_OUTPUT,
568 "Constant expression reduced to (%s) %8.8X%8.8X\n\n",
570 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
573 case ACPI_TYPE_STRING:
575 Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
576 Op->Common.AmlOpcode = AML_STRING_OP;
577 Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1;
578 Op->Common.Value.String = ObjDesc->String.Pointer;
580 DbgPrint (ASL_PARSE_OUTPUT,
581 "Constant expression reduced to (STRING) %s\n\n",
582 Op->Common.Value.String);
586 case ACPI_TYPE_BUFFER:
588 Op->Asl.ParseOpcode = PARSEOP_BUFFER;
589 Op->Common.AmlOpcode = AML_BUFFER_OP;
590 Op->Asl.CompileFlags = NODE_AML_PACKAGE;
591 UtSetParseOpName (Op);
593 /* Child node is the buffer length */
595 RootOp = TrAllocateNode (PARSEOP_INTEGER);
597 RootOp->Asl.AmlOpcode = AML_DWORD_OP;
598 RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
599 RootOp->Asl.Parent = Op;
601 (void) OpcSetOptimalIntegerSize (RootOp);
603 Op->Asl.Child = RootOp;
605 UtSetParseOpName (Op);
607 /* Peer to the child is the raw buffer data */
609 RootOp = TrAllocateNode (PARSEOP_RAW_DATA);
610 RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
611 RootOp->Asl.AmlLength = ObjDesc->Buffer.Length;
612 RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer;
613 RootOp->Asl.Parent = Op->Asl.Parent;
615 Op->Asl.Next = RootOp;
618 DbgPrint (ASL_PARSE_OUTPUT,
619 "Constant expression reduced to (BUFFER) length %X\n\n",
620 ObjDesc->Buffer.Length);
629 /*******************************************************************************
631 * FUNCTION: OpcUpdateIntegerNode
633 * PARAMETERS: Op - Current parse object
634 * Value - Value for the integer op
638 * DESCRIPTION: Update node to the correct Integer type and value
640 ******************************************************************************/
643 OpcUpdateIntegerNode (
644 ACPI_PARSE_OBJECT *Op,
648 Op->Common.Value.Integer = Value;
651 * The AmlLength is used by the parser to indicate a constant,
652 * (if non-zero). Length is either (1/2/4/8)
654 switch (Op->Asl.AmlLength)
658 TrUpdateNode (PARSEOP_BYTECONST, Op);
659 Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
664 TrUpdateNode (PARSEOP_WORDCONST, Op);
665 Op->Asl.AmlOpcode = AML_RAW_DATA_WORD;
670 TrUpdateNode (PARSEOP_DWORDCONST, Op);
671 Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD;
676 TrUpdateNode (PARSEOP_QWORDCONST, Op);
677 Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD;
683 OpcSetOptimalIntegerSize (Op);
684 TrUpdateNode (PARSEOP_INTEGER, Op);
688 Op->Asl.AmlLength = 0;
692 /*******************************************************************************
694 * FUNCTION: OpcAmlEvaluationWalk1
696 * PARAMETERS: ASL_WALK_CALLBACK
700 * DESCRIPTION: Descending callback for AML execution of constant subtrees
702 ******************************************************************************/
705 OpcAmlEvaluationWalk1 (
706 ACPI_PARSE_OBJECT *Op,
710 ACPI_WALK_STATE *WalkState = Context;
712 ACPI_PARSE_OBJECT *OutOp;
716 WalkState->Opcode = Op->Common.AmlOpcode;
717 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
719 /* Copy child pointer to Arg for compatibility with Interpreter */
723 Op->Common.Value.Arg = Op->Asl.Child;
726 /* Call AML dispatcher */
728 Status = AcpiDsExecBeginOp (WalkState, &OutOp);
729 if (ACPI_FAILURE (Status))
731 DbgPrint (ASL_PARSE_OUTPUT,
732 "%s Constant interpretation failed (1) - %s\n",
733 Op->Asl.ParseOpName, AcpiFormatException (Status));
740 /*******************************************************************************
742 * FUNCTION: OpcAmlEvaluationWalk2
744 * PARAMETERS: ASL_WALK_CALLBACK
748 * DESCRIPTION: Ascending callback for AML execution of constant subtrees
750 ******************************************************************************/
753 OpcAmlEvaluationWalk2 (
754 ACPI_PARSE_OBJECT *Op,
758 ACPI_WALK_STATE *WalkState = Context;
763 WalkState->Opcode = Op->Common.AmlOpcode;
764 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
766 /* Copy child pointer to Arg for compatibility with Interpreter */
770 Op->Common.Value.Arg = Op->Asl.Child;
773 /* Call AML dispatcher */
775 Status = AcpiDsExecEndOp (WalkState);
776 if (ACPI_FAILURE (Status))
778 DbgPrint (ASL_PARSE_OUTPUT,
779 "%s: Constant interpretation failed (2) - %s\n",
780 Op->Asl.ParseOpName, AcpiFormatException (Status));