acpica.library: Initial import of Intel ACPICA, v20131115
[AROS.git] / arch / all-pc / acpica / source / compiler / aslfold.c
blob9a041a56a1c2961efe3a6ae83d48b25ca4727508
1 /******************************************************************************
3 * Module Name: aslfold - Constant folding
5 *****************************************************************************/
7 /*
8 * Copyright (C) 2000 - 2013, Intel Corp.
9 * All rights reserved.
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.
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.
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.
45 #include "aslcompiler.h"
46 #include "aslcompiler.y.h"
47 #include "amlcode.h"
49 #include "acdispat.h"
50 #include "acparser.h"
52 #define _COMPONENT ACPI_COMPILER
53 ACPI_MODULE_NAME ("aslfold")
55 /* Local prototypes */
57 static ACPI_STATUS
58 OpcAmlEvaluationWalk1 (
59 ACPI_PARSE_OBJECT *Op,
60 UINT32 Level,
61 void *Context);
63 static ACPI_STATUS
64 OpcAmlEvaluationWalk2 (
65 ACPI_PARSE_OBJECT *Op,
66 UINT32 Level,
67 void *Context);
69 static ACPI_STATUS
70 OpcAmlCheckForConstant (
71 ACPI_PARSE_OBJECT *Op,
72 UINT32 Level,
73 void *Context);
75 static void
76 OpcUpdateIntegerNode (
77 ACPI_PARSE_OBJECT *Op,
78 UINT64 Value);
81 /*******************************************************************************
83 * FUNCTION: OpcAmlEvaluationWalk1
85 * PARAMETERS: ASL_WALK_CALLBACK
87 * RETURN: Status
89 * DESCRIPTION: Descending callback for AML execution of constant subtrees
91 ******************************************************************************/
93 static ACPI_STATUS
94 OpcAmlEvaluationWalk1 (
95 ACPI_PARSE_OBJECT *Op,
96 UINT32 Level,
97 void *Context)
99 ACPI_WALK_STATE *WalkState = Context;
100 ACPI_STATUS Status;
101 ACPI_PARSE_OBJECT *OutOp;
104 WalkState->Op = Op;
105 WalkState->Opcode = Op->Common.AmlOpcode;
106 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
108 /* Copy child pointer to Arg for compatibility with Interpreter */
110 if (Op->Asl.Child)
112 Op->Common.Value.Arg = Op->Asl.Child;
115 /* Call AML dispatcher */
117 Status = AcpiDsExecBeginOp (WalkState, &OutOp);
118 if (ACPI_FAILURE (Status))
120 AcpiOsPrintf ("Constant interpretation failed - %s\n",
121 AcpiFormatException (Status));
124 return (Status);
128 /*******************************************************************************
130 * FUNCTION: OpcAmlEvaluationWalk2
132 * PARAMETERS: ASL_WALK_CALLBACK
134 * RETURN: Status
136 * DESCRIPTION: Ascending callback for AML execution of constant subtrees
138 ******************************************************************************/
140 static ACPI_STATUS
141 OpcAmlEvaluationWalk2 (
142 ACPI_PARSE_OBJECT *Op,
143 UINT32 Level,
144 void *Context)
146 ACPI_WALK_STATE *WalkState = Context;
147 ACPI_STATUS Status;
150 WalkState->Op = Op;
151 WalkState->Opcode = Op->Common.AmlOpcode;
152 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
154 /* Copy child pointer to Arg for compatibility with Interpreter */
156 if (Op->Asl.Child)
158 Op->Common.Value.Arg = Op->Asl.Child;
161 /* Call AML dispatcher */
163 Status = AcpiDsExecEndOp (WalkState);
164 if (ACPI_FAILURE (Status))
166 AcpiOsPrintf ("Constant interpretation failed - %s\n",
167 AcpiFormatException (Status));
170 return (Status);
174 /*******************************************************************************
176 * FUNCTION: OpcAmlCheckForConstant
178 * PARAMETERS: ASL_WALK_CALLBACK
180 * RETURN: Status
182 * DESCRIPTION: Check one Op for a type 3/4/5 AML opcode
184 ******************************************************************************/
186 static ACPI_STATUS
187 OpcAmlCheckForConstant (
188 ACPI_PARSE_OBJECT *Op,
189 UINT32 Level,
190 void *Context)
192 ACPI_WALK_STATE *WalkState = Context;
195 WalkState->Op = Op;
196 WalkState->Opcode = Op->Common.AmlOpcode;
197 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
199 DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ",
200 Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
203 * These opcodes do not appear in the OpcodeInfo table, but
204 * they represent constants, so abort the constant walk now.
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))
211 WalkState->WalkType = ACPI_WALK_CONST_OPTIONAL;
212 return (AE_TYPE);
215 if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
217 /* The opcode is not a Type 3/4/5 opcode */
219 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
221 DbgPrint (ASL_PARSE_OUTPUT,
222 "**** Valid Target, cannot reduce ****\n");
224 else
226 DbgPrint (ASL_PARSE_OUTPUT,
227 "**** Not a Type 3/4/5 opcode ****\n");
230 if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
233 * We are looking at at normal expression to see if it can be
234 * reduced. It can't. No error
236 return (AE_TYPE);
240 * This is an expression that MUST reduce to a constant, and it
241 * can't be reduced. This is an error
243 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
245 AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op,
246 Op->Asl.ParseOpName);
248 else
250 AslError (ASL_ERROR, ASL_MSG_INVALID_CONSTANT_OP, Op,
251 Op->Asl.ParseOpName);
254 return (AE_TYPE);
257 /* Debug output */
259 DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345");
261 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
263 DbgPrint (ASL_PARSE_OUTPUT, " TARGET");
265 if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
267 DbgPrint (ASL_PARSE_OUTPUT, " TERMARG");
270 DbgPrint (ASL_PARSE_OUTPUT, "\n");
271 return (AE_OK);
275 /*******************************************************************************
277 * FUNCTION: OpcAmlConstantWalk
279 * PARAMETERS: ASL_WALK_CALLBACK
281 * RETURN: Status
283 * DESCRIPTION: Reduce an Op and its subtree to a constant if possible
285 ******************************************************************************/
287 ACPI_STATUS
288 OpcAmlConstantWalk (
289 ACPI_PARSE_OBJECT *Op,
290 UINT32 Level,
291 void *Context)
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;
302 * Only interested in subtrees that could possibly contain
303 * expressions that can be evaluated at this time
305 if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) ||
306 (Op->Asl.CompileFlags & NODE_IS_TARGET))
308 return (AE_OK);
311 /* Set the walk type based on the reduction used for this op */
313 if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
315 /* Op is a TermArg, constant folding is merely optional */
317 if (!Gbl_FoldConstants)
319 return (AE_CTRL_DEPTH);
322 WalkType = ACPI_WALK_CONST_OPTIONAL;
324 else
326 /* Op is a DataObject, the expression MUST reduced to a constant */
328 WalkType = ACPI_WALK_CONST_REQUIRED;
331 /* Create a new walk state */
333 WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
334 if (!WalkState)
336 return (AE_NO_MEMORY);
339 WalkState->NextOp = NULL;
340 WalkState->Params = NULL;
341 WalkState->WalkType = WalkType;
342 WalkState->CallerReturnDesc = &ObjDesc;
345 * Examine the entire subtree -- all nodes must be constants
346 * or type 3/4/5 opcodes
348 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
349 OpcAmlCheckForConstant, NULL, WalkState);
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)
355 if (Status == AE_TYPE)
357 /* Subtree cannot be reduced to a constant */
359 if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
361 AcpiDsDeleteWalkState (WalkState);
362 return (AE_OK);
365 /* Don't descend any further, and use a default "constant" value */
367 Status = AE_CTRL_DEPTH;
369 else
371 /* Subtree can be reduced */
373 /* Allocate a new temporary root for this subtree */
375 RootOp = TrAllocateNode (PARSEOP_INTEGER);
376 if (!RootOp)
378 return (AE_NO_MEMORY);
381 RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
383 OriginalParentOp = Op->Common.Parent;
384 Op->Common.Parent = RootOp;
386 /* Hand off the subtree to the AML interpreter */
388 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
389 OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
390 Op->Common.Parent = OriginalParentOp;
392 /* TBD: we really *should* release the RootOp node */
394 if (ACPI_SUCCESS (Status))
396 TotalFolds++;
398 /* Get the final result */
400 Status = AcpiDsResultPop (&ObjDesc, WalkState);
403 /* Check for error from the ACPICA core */
405 if (ACPI_FAILURE (Status))
407 AslCoreSubsystemError (Op, Status,
408 "Failure during constant evaluation", FALSE);
412 if (ACPI_FAILURE (Status))
414 /* We could not resolve the subtree for some reason */
416 AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
417 Op->Asl.ParseOpName);
419 /* Set the subtree value to ZERO anyway. Eliminates further errors */
421 OpcUpdateIntegerNode (Op, 0);
423 else
425 AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
426 Op->Asl.ParseOpName);
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.
432 switch (ObjDesc->Common.Type)
434 case ACPI_TYPE_INTEGER:
436 OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value);
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;
444 case ACPI_TYPE_STRING:
446 Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
447 Op->Common.AmlOpcode = AML_STRING_OP;
448 Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1;
449 Op->Common.Value.String = ObjDesc->String.Pointer;
451 DbgPrint (ASL_PARSE_OUTPUT,
452 "Constant expression reduced to (STRING) %s\n",
453 Op->Common.Value.String);
455 break;
457 case ACPI_TYPE_BUFFER:
459 Op->Asl.ParseOpcode = PARSEOP_BUFFER;
460 Op->Common.AmlOpcode = AML_BUFFER_OP;
461 Op->Asl.CompileFlags = NODE_AML_PACKAGE;
462 UtSetParseOpName (Op);
464 /* Child node is the buffer length */
466 RootOp = TrAllocateNode (PARSEOP_INTEGER);
468 RootOp->Asl.AmlOpcode = AML_DWORD_OP;
469 RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
470 RootOp->Asl.Parent = Op;
472 (void) OpcSetOptimalIntegerSize (RootOp);
474 Op->Asl.Child = RootOp;
475 Op = RootOp;
476 UtSetParseOpName (Op);
478 /* Peer to the child is the raw buffer data */
480 RootOp = TrAllocateNode (PARSEOP_RAW_DATA);
481 RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
482 RootOp->Asl.AmlLength = ObjDesc->Buffer.Length;
483 RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer;
484 RootOp->Asl.Parent = Op->Asl.Parent;
486 Op->Asl.Next = RootOp;
487 Op = RootOp;
489 DbgPrint (ASL_PARSE_OUTPUT,
490 "Constant expression reduced to (BUFFER) length %X\n",
491 ObjDesc->Buffer.Length);
492 break;
494 default:
496 printf ("Unsupported return type: %s\n",
497 AcpiUtGetObjectTypeName (ObjDesc));
498 break;
502 UtSetParseOpName (Op);
503 Op->Asl.Child = NULL;
505 AcpiDsDeleteWalkState (WalkState);
506 return (AE_CTRL_DEPTH);
510 /*******************************************************************************
512 * FUNCTION: OpcUpdateIntegerNode
514 * PARAMETERS: Op - Current parse object
516 * RETURN: None
518 * DESCRIPTION: Update node to the correct integer type.
520 ******************************************************************************/
522 static void
523 OpcUpdateIntegerNode (
524 ACPI_PARSE_OBJECT *Op,
525 UINT64 Value)
528 Op->Common.Value.Integer = Value;
531 * The AmlLength is used by the parser to indicate a constant,
532 * (if non-zero). Length is either (1/2/4/8)
534 switch (Op->Asl.AmlLength)
536 case 1:
538 TrUpdateNode (PARSEOP_BYTECONST, Op);
539 Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
540 break;
542 case 2:
544 TrUpdateNode (PARSEOP_WORDCONST, Op);
545 Op->Asl.AmlOpcode = AML_RAW_DATA_WORD;
546 break;
548 case 4:
550 TrUpdateNode (PARSEOP_DWORDCONST, Op);
551 Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD;
552 break;
554 case 8:
556 TrUpdateNode (PARSEOP_QWORDCONST, Op);
557 Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD;
558 break;
560 case 0:
561 default:
563 OpcSetOptimalIntegerSize (Op);
564 TrUpdateNode (PARSEOP_INTEGER, Op);
565 break;
568 Op->Asl.AmlLength = 0;