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)
239 DbgPrint (ASL_PARSE_OUTPUT,
240 "\nBuffer+Buffer->Buffer constant reduction is not supported yet");
246 * These opcodes do not appear in the OpcodeInfo table, but
247 * they represent constants, so abort the constant walk now.
249 if ((WalkState->Opcode == AML_RAW_DATA_BYTE) ||
250 (WalkState->Opcode == AML_RAW_DATA_WORD) ||
251 (WalkState->Opcode == AML_RAW_DATA_DWORD) ||
252 (WalkState->Opcode == AML_RAW_DATA_QWORD))
254 DbgPrint (ASL_PARSE_OUTPUT, "RAW DATA");
259 /* Type 3/4/5 opcodes have the AML_CONSTANT flag set */
261 if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
263 /* Not 3/4/5 opcode, but maybe can convert to STORE */
265 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
267 DbgPrint (ASL_PARSE_OUTPUT,
268 "**** Valid Target, transform to Store ****\n");
269 return (AE_CTRL_RETURN_VALUE);
272 /* Expression cannot be reduced */
274 DbgPrint (ASL_PARSE_OUTPUT,
275 "**** Not a Type 3/4/5 opcode (%s) ****",
276 Op->Asl.ParseOpName);
284 DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345");
286 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
288 if (Op->Asl.ParseOpcode == PARSEOP_ZERO)
290 DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " NULL TARGET");
294 DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " VALID TARGET");
297 if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
299 DbgPrint (ASL_PARSE_OUTPUT, "%-16s", " TERMARG");
304 /* Dump the node compile flags also */
306 TrPrintNodeCompileFlags (Op->Asl.CompileFlags);
307 DbgPrint (ASL_PARSE_OUTPUT, "\n");
312 /*******************************************************************************
314 * FUNCTION: TrSimpleConstantReduction
316 * PARAMETERS: Op - Parent operator to be transformed
317 * WalkState - Current walk state
321 * DESCRIPTION: Reduce an entire AML operation to a single constant. The
322 * operation must not have a target operand.
326 ******************************************************************************/
329 TrSimpleConstantReduction (
330 ACPI_PARSE_OBJECT *Op,
331 ACPI_WALK_STATE *WalkState)
333 ACPI_PARSE_OBJECT *RootOp;
334 ACPI_PARSE_OBJECT *OriginalParentOp;
335 ACPI_OPERAND_OBJECT *ObjDesc;
339 DbgPrint (ASL_PARSE_OUTPUT,
340 "Simple subtree constant reduction, operator to constant\n");
342 /* Allocate a new temporary root for this subtree */
344 RootOp = TrAllocateNode (PARSEOP_INTEGER);
347 return (AE_NO_MEMORY);
350 RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
352 OriginalParentOp = Op->Common.Parent;
353 Op->Common.Parent = RootOp;
355 /* Hand off the subtree to the AML interpreter */
357 WalkState->CallerReturnDesc = &ObjDesc;
359 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
360 OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
362 /* Restore original parse tree */
364 Op->Common.Parent = OriginalParentOp;
366 if (ACPI_FAILURE (Status))
368 DbgPrint (ASL_PARSE_OUTPUT,
369 "Constant Subtree evaluation(1), %s\n",
370 AcpiFormatException (Status));
374 /* Get the final result */
376 Status = AcpiDsResultPop (&ObjDesc, WalkState);
377 if (ACPI_FAILURE (Status))
379 DbgPrint (ASL_PARSE_OUTPUT,
380 "Constant Subtree evaluation(2), %s\n",
381 AcpiFormatException (Status));
385 /* Disconnect any existing children, install new constant */
387 Op->Asl.Child = NULL;
388 TrInstallReducedConstant (Op, ObjDesc);
390 UtSetParseOpName (Op);
395 /*******************************************************************************
397 * FUNCTION: TrTransformToStoreOp
399 * PARAMETERS: Op - Parent operator to be transformed
400 * WalkState - Current walk state
404 * DESCRIPTION: Transforms a single AML operation with a constant and target
405 * to a simple store operation:
407 * Add (32,64,DATA) --> Store (96,DATA)
409 ******************************************************************************/
412 TrTransformToStoreOp (
413 ACPI_PARSE_OBJECT *Op,
414 ACPI_WALK_STATE *WalkState)
416 ACPI_PARSE_OBJECT *OriginalTarget;
417 ACPI_PARSE_OBJECT *NewTarget;
418 ACPI_PARSE_OBJECT *Child1;
419 ACPI_PARSE_OBJECT *Child2;
420 ACPI_OPERAND_OBJECT *ObjDesc;
421 ACPI_PARSE_OBJECT *NewParent;
422 ACPI_PARSE_OBJECT *OriginalParent;
426 DbgPrint (ASL_PARSE_OUTPUT,
427 "Reduction/Transform to StoreOp: Store(Constant, Target)\n");
429 /* Extract the operands */
431 Child1 = Op->Asl.Child;
432 Child2 = Child1->Asl.Next;
435 * Special case for DIVIDE -- it has two targets. The first
436 * is for the remainder and if present, we will not attempt
437 * to reduce the expression.
439 if (Op->Asl.ParseOpcode == PARSEOP_DIVIDE)
441 Child2 = Child2->Asl.Next;
442 if (Child2->Asl.ParseOpcode != PARSEOP_ZERO)
444 DbgPrint (ASL_PARSE_OUTPUT,
445 "Cannot reduce DIVIDE - has two targets\n\n");
451 * Create a NULL (zero) target so that we can use the
452 * interpreter to evaluate the expression.
454 NewTarget = TrCreateNullTarget ();
455 NewTarget->Common.AmlOpcode = AML_INT_NAMEPATH_OP;
457 /* Handle one-operand cases (NOT, TOBCD, etc.) */
459 if (!Child2->Asl.Next)
464 /* Link in new NULL target as the last operand */
466 OriginalTarget = Child2->Asl.Next;
467 Child2->Asl.Next = NewTarget;
468 NewTarget->Asl.Parent = OriginalTarget->Asl.Parent;
470 NewParent = TrAllocateNode (PARSEOP_INTEGER);
471 NewParent->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
473 OriginalParent = Op->Common.Parent;
474 Op->Common.Parent = NewParent;
476 /* Hand off the subtree to the AML interpreter */
478 WalkState->CallerReturnDesc = &ObjDesc;
480 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
481 OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
482 if (ACPI_FAILURE (Status))
484 DbgPrint (ASL_PARSE_OUTPUT,
485 "Constant Subtree evaluation(3), %s\n",
486 AcpiFormatException (Status));
490 /* Get the final result */
492 Status = AcpiDsResultPop (&ObjDesc, WalkState);
493 if (ACPI_FAILURE (Status))
495 DbgPrint (ASL_PARSE_OUTPUT,
496 "Constant Subtree evaluation(4), %s\n",
497 AcpiFormatException (Status));
501 /* Truncate any subtree expressions, they have been evaluated */
503 Child1->Asl.Child = NULL;
505 /* Folded constant is in ObjDesc, store into Child1 */
507 TrInstallReducedConstant (Child1, ObjDesc);
509 /* Convert operator to STORE */
511 Op->Asl.ParseOpcode = PARSEOP_STORE;
512 Op->Asl.AmlOpcode = AML_STORE_OP;
513 UtSetParseOpName (Op);
514 Op->Common.Parent = OriginalParent;
516 /* First child is the folded constant */
518 /* Second child will be the target */
520 Child1->Asl.Next = OriginalTarget;
526 /* Restore original links */
528 Op->Common.Parent = OriginalParent;
529 Child2->Asl.Next = OriginalTarget;
534 /*******************************************************************************
536 * FUNCTION: TrInstallReducedConstant
538 * PARAMETERS: Op - Parent operator to be transformed
539 * ObjDesc - Reduced constant to be installed
543 * DESCRIPTION: Transform the original operator to a simple constant.
544 * Handles Integers, Strings, and Buffers.
546 ******************************************************************************/
549 TrInstallReducedConstant (
550 ACPI_PARSE_OBJECT *Op,
551 ACPI_OPERAND_OBJECT *ObjDesc)
553 ACPI_PARSE_OBJECT *LengthOp;
554 ACPI_PARSE_OBJECT *DataOp;
558 AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
559 Op->Asl.ParseOpName);
562 * Because we know we executed type 3/4/5 opcodes above, we know that
563 * the result must be either an Integer, String, or Buffer.
565 switch (ObjDesc->Common.Type)
567 case ACPI_TYPE_INTEGER:
569 OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value);
571 DbgPrint (ASL_PARSE_OUTPUT,
572 "Constant expression reduced to (%s) %8.8X%8.8X\n\n",
574 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
577 case ACPI_TYPE_STRING:
579 Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
580 Op->Common.AmlOpcode = AML_STRING_OP;
581 Op->Asl.AmlLength = strlen (ObjDesc->String.Pointer) + 1;
582 Op->Common.Value.String = ObjDesc->String.Pointer;
584 DbgPrint (ASL_PARSE_OUTPUT,
585 "Constant expression reduced to (STRING) %s\n\n",
586 Op->Common.Value.String);
589 case ACPI_TYPE_BUFFER:
591 * Create a new parse subtree of the form:
593 * BUFFER (Buffer AML opcode)
594 * INTEGER (Buffer length in bytes)
595 * RAW_DATA (Buffer byte data)
597 Op->Asl.ParseOpcode = PARSEOP_BUFFER;
598 Op->Common.AmlOpcode = AML_BUFFER_OP;
599 Op->Asl.CompileFlags = NODE_AML_PACKAGE;
600 UtSetParseOpName (Op);
602 /* Child node is the buffer length */
604 LengthOp = TrAllocateNode (PARSEOP_INTEGER);
606 LengthOp->Asl.AmlOpcode = AML_DWORD_OP;
607 LengthOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
608 LengthOp->Asl.Parent = Op;
609 (void) OpcSetOptimalIntegerSize (LengthOp);
611 Op->Asl.Child = LengthOp;
613 /* Next child is the raw buffer data */
615 DataOp = TrAllocateNode (PARSEOP_RAW_DATA);
616 DataOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
617 DataOp->Asl.AmlLength = ObjDesc->Buffer.Length;
618 DataOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer;
619 DataOp->Asl.Parent = Op;
621 LengthOp->Asl.Next = DataOp;
623 DbgPrint (ASL_PARSE_OUTPUT,
624 "Constant expression reduced to (BUFFER) length %X\n\n",
625 ObjDesc->Buffer.Length);
634 /*******************************************************************************
636 * FUNCTION: OpcUpdateIntegerNode
638 * PARAMETERS: Op - Current parse object
639 * Value - Value for the integer op
643 * DESCRIPTION: Update node to the correct Integer type and value
645 ******************************************************************************/
648 OpcUpdateIntegerNode (
649 ACPI_PARSE_OBJECT *Op,
653 Op->Common.Value.Integer = Value;
656 * The AmlLength is used by the parser to indicate a constant,
657 * (if non-zero). Length is either (1/2/4/8)
659 switch (Op->Asl.AmlLength)
663 TrUpdateNode (PARSEOP_BYTECONST, Op);
664 Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
669 TrUpdateNode (PARSEOP_WORDCONST, Op);
670 Op->Asl.AmlOpcode = AML_RAW_DATA_WORD;
675 TrUpdateNode (PARSEOP_DWORDCONST, Op);
676 Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD;
681 TrUpdateNode (PARSEOP_QWORDCONST, Op);
682 Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD;
688 OpcSetOptimalIntegerSize (Op);
689 TrUpdateNode (PARSEOP_INTEGER, Op);
693 Op->Asl.AmlLength = 0;
697 /*******************************************************************************
699 * FUNCTION: OpcAmlEvaluationWalk1
701 * PARAMETERS: ASL_WALK_CALLBACK
705 * DESCRIPTION: Descending callback for AML execution of constant subtrees
707 ******************************************************************************/
710 OpcAmlEvaluationWalk1 (
711 ACPI_PARSE_OBJECT *Op,
715 ACPI_WALK_STATE *WalkState = Context;
717 ACPI_PARSE_OBJECT *OutOp;
721 WalkState->Opcode = Op->Common.AmlOpcode;
722 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
724 /* Copy child pointer to Arg for compatibility with Interpreter */
728 Op->Common.Value.Arg = Op->Asl.Child;
731 /* Call AML dispatcher */
733 Status = AcpiDsExecBeginOp (WalkState, &OutOp);
734 if (ACPI_FAILURE (Status))
736 DbgPrint (ASL_PARSE_OUTPUT,
737 "%s Constant interpretation failed (1) - %s\n",
738 Op->Asl.ParseOpName, AcpiFormatException (Status));
745 /*******************************************************************************
747 * FUNCTION: OpcAmlEvaluationWalk2
749 * PARAMETERS: ASL_WALK_CALLBACK
753 * DESCRIPTION: Ascending callback for AML execution of constant subtrees
755 ******************************************************************************/
758 OpcAmlEvaluationWalk2 (
759 ACPI_PARSE_OBJECT *Op,
763 ACPI_WALK_STATE *WalkState = Context;
768 WalkState->Opcode = Op->Common.AmlOpcode;
769 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
771 /* Copy child pointer to Arg for compatibility with Interpreter */
775 Op->Common.Value.Arg = Op->Asl.Child;
778 /* Call AML dispatcher */
780 Status = AcpiDsExecEndOp (WalkState);
781 if (ACPI_FAILURE (Status))
783 DbgPrint (ASL_PARSE_OUTPUT,
784 "%s: Constant interpretation failed (2) - %s\n",
785 Op->Asl.ParseOpName, AcpiFormatException (Status));