aslfold.c revision 1.1.1.3 1 /******************************************************************************
2 *
3 * Module Name: aslfold - Constant folding
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2013, Intel Corp.
9 * All rights reserved.
10 *
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.
25 *
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.
29 *
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.
42 */
43
44
45 #include "aslcompiler.h"
46 #include "aslcompiler.y.h"
47 #include "amlcode.h"
48
49 #include "acdispat.h"
50 #include "acparser.h"
51
52 #define _COMPONENT ACPI_COMPILER
53 ACPI_MODULE_NAME ("aslfold")
54
55 /* Local prototypes */
56
57 static ACPI_STATUS
58 OpcAmlEvaluationWalk1 (
59 ACPI_PARSE_OBJECT *Op,
60 UINT32 Level,
61 void *Context);
62
63 static ACPI_STATUS
64 OpcAmlEvaluationWalk2 (
65 ACPI_PARSE_OBJECT *Op,
66 UINT32 Level,
67 void *Context);
68
69 static ACPI_STATUS
70 OpcAmlCheckForConstant (
71 ACPI_PARSE_OBJECT *Op,
72 UINT32 Level,
73 void *Context);
74
75 static void
76 OpcUpdateIntegerNode (
77 ACPI_PARSE_OBJECT *Op,
78 UINT64 Value);
79
80
81 /*******************************************************************************
82 *
83 * FUNCTION: OpcAmlEvaluationWalk1
84 *
85 * PARAMETERS: ASL_WALK_CALLBACK
86 *
87 * RETURN: Status
88 *
89 * DESCRIPTION: Descending callback for AML execution of constant subtrees
90 *
91 ******************************************************************************/
92
93 static ACPI_STATUS
94 OpcAmlEvaluationWalk1 (
95 ACPI_PARSE_OBJECT *Op,
96 UINT32 Level,
97 void *Context)
98 {
99 ACPI_WALK_STATE *WalkState = Context;
100 ACPI_STATUS Status;
101 ACPI_PARSE_OBJECT *OutOp;
102
103
104 WalkState->Op = Op;
105 WalkState->Opcode = Op->Common.AmlOpcode;
106 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
107
108 /* Copy child pointer to Arg for compatibility with Interpreter */
109
110 if (Op->Asl.Child)
111 {
112 Op->Common.Value.Arg = Op->Asl.Child;
113 }
114
115 /* Call AML dispatcher */
116
117 Status = AcpiDsExecBeginOp (WalkState, &OutOp);
118 if (ACPI_FAILURE (Status))
119 {
120 AcpiOsPrintf ("Constant interpretation failed - %s\n",
121 AcpiFormatException (Status));
122 }
123
124 return (Status);
125 }
126
127
128 /*******************************************************************************
129 *
130 * FUNCTION: OpcAmlEvaluationWalk2
131 *
132 * PARAMETERS: ASL_WALK_CALLBACK
133 *
134 * RETURN: Status
135 *
136 * DESCRIPTION: Ascending callback for AML execution of constant subtrees
137 *
138 ******************************************************************************/
139
140 static ACPI_STATUS
141 OpcAmlEvaluationWalk2 (
142 ACPI_PARSE_OBJECT *Op,
143 UINT32 Level,
144 void *Context)
145 {
146 ACPI_WALK_STATE *WalkState = Context;
147 ACPI_STATUS Status;
148
149
150 WalkState->Op = Op;
151 WalkState->Opcode = Op->Common.AmlOpcode;
152 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
153
154 /* Copy child pointer to Arg for compatibility with Interpreter */
155
156 if (Op->Asl.Child)
157 {
158 Op->Common.Value.Arg = Op->Asl.Child;
159 }
160
161 /* Call AML dispatcher */
162
163 Status = AcpiDsExecEndOp (WalkState);
164 if (ACPI_FAILURE (Status))
165 {
166 AcpiOsPrintf ("Constant interpretation failed - %s\n",
167 AcpiFormatException (Status));
168 }
169
170 return (Status);
171 }
172
173
174 /*******************************************************************************
175 *
176 * FUNCTION: OpcAmlCheckForConstant
177 *
178 * PARAMETERS: ASL_WALK_CALLBACK
179 *
180 * RETURN: Status
181 *
182 * DESCRIPTION: Check one Op for a type 3/4/5 AML opcode
183 *
184 ******************************************************************************/
185
186 static ACPI_STATUS
187 OpcAmlCheckForConstant (
188 ACPI_PARSE_OBJECT *Op,
189 UINT32 Level,
190 void *Context)
191 {
192 ACPI_WALK_STATE *WalkState = Context;
193
194
195 WalkState->Op = Op;
196 WalkState->Opcode = Op->Common.AmlOpcode;
197 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
198
199 DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ",
200 Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName);
201
202 /*
203 * These opcodes do not appear in the OpcodeInfo table, but
204 * they represent constants, so abort the constant walk now.
205 */
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))
210 {
211 WalkState->WalkType = ACPI_WALK_CONST_OPTIONAL;
212 return (AE_TYPE);
213 }
214
215 if (!(WalkState->OpInfo->Flags & AML_CONSTANT))
216 {
217 /* The opcode is not a Type 3/4/5 opcode */
218
219 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
220 {
221 DbgPrint (ASL_PARSE_OUTPUT,
222 "**** Valid Target, cannot reduce ****\n");
223 }
224 else
225 {
226 DbgPrint (ASL_PARSE_OUTPUT,
227 "**** Not a Type 3/4/5 opcode ****\n");
228 }
229
230 if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
231 {
232 /*
233 * We are looking at at normal expression to see if it can be
234 * reduced. It can't. No error
235 */
236 return (AE_TYPE);
237 }
238
239 /*
240 * This is an expression that MUST reduce to a constant, and it
241 * can't be reduced. This is an error
242 */
243 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
244 {
245 AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op,
246 Op->Asl.ParseOpName);
247 }
248 else
249 {
250 AslError (ASL_ERROR, ASL_MSG_INVALID_CONSTANT_OP, Op,
251 Op->Asl.ParseOpName);
252 }
253
254 return (AE_TYPE);
255 }
256
257 /* Debug output */
258
259 DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345");
260
261 if (Op->Asl.CompileFlags & NODE_IS_TARGET)
262 {
263 DbgPrint (ASL_PARSE_OUTPUT, " TARGET");
264 }
265 if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
266 {
267 DbgPrint (ASL_PARSE_OUTPUT, " TERMARG");
268 }
269
270 DbgPrint (ASL_PARSE_OUTPUT, "\n");
271 return (AE_OK);
272 }
273
274
275 /*******************************************************************************
276 *
277 * FUNCTION: OpcAmlConstantWalk
278 *
279 * PARAMETERS: ASL_WALK_CALLBACK
280 *
281 * RETURN: Status
282 *
283 * DESCRIPTION: Reduce an Op and its subtree to a constant if possible
284 *
285 ******************************************************************************/
286
287 ACPI_STATUS
288 OpcAmlConstantWalk (
289 ACPI_PARSE_OBJECT *Op,
290 UINT32 Level,
291 void *Context)
292 {
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;
299
300
301 /*
302 * Only interested in subtrees that could possibly contain
303 * expressions that can be evaluated at this time
304 */
305 if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) ||
306 (Op->Asl.CompileFlags & NODE_IS_TARGET))
307 {
308 return (AE_OK);
309 }
310
311 /* Set the walk type based on the reduction used for this op */
312
313 if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG)
314 {
315 /* Op is a TermArg, constant folding is merely optional */
316
317 if (!Gbl_FoldConstants)
318 {
319 return (AE_CTRL_DEPTH);
320 }
321
322 WalkType = ACPI_WALK_CONST_OPTIONAL;
323 }
324 else
325 {
326 /* Op is a DataObject, the expression MUST reduced to a constant */
327
328 WalkType = ACPI_WALK_CONST_REQUIRED;
329 }
330
331 /* Create a new walk state */
332
333 WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
334 if (!WalkState)
335 {
336 return (AE_NO_MEMORY);
337 }
338
339 WalkState->NextOp = NULL;
340 WalkState->Params = NULL;
341 WalkState->WalkType = WalkType;
342 WalkState->CallerReturnDesc = &ObjDesc;
343
344 /*
345 * Examine the entire subtree -- all nodes must be constants
346 * or type 3/4/5 opcodes
347 */
348 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD,
349 OpcAmlCheckForConstant, NULL, WalkState);
350
351 /*
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)
354 */
355 if (Status == AE_TYPE)
356 {
357 /* Subtree cannot be reduced to a constant */
358
359 if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL)
360 {
361 AcpiDsDeleteWalkState (WalkState);
362 return (AE_OK);
363 }
364
365 /* Don't descend any further, and use a default "constant" value */
366
367 Status = AE_CTRL_DEPTH;
368 }
369 else
370 {
371 /* Subtree can be reduced */
372
373 /* Allocate a new temporary root for this subtree */
374
375 RootOp = TrAllocateNode (PARSEOP_INTEGER);
376 if (!RootOp)
377 {
378 return (AE_NO_MEMORY);
379 }
380
381 RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP;
382
383 OriginalParentOp = Op->Common.Parent;
384 Op->Common.Parent = RootOp;
385
386 /* Hand off the subtree to the AML interpreter */
387
388 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE,
389 OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState);
390 Op->Common.Parent = OriginalParentOp;
391
392 /* TBD: we really *should* release the RootOp node */
393
394 if (ACPI_SUCCESS (Status))
395 {
396 TotalFolds++;
397
398 /* Get the final result */
399
400 Status = AcpiDsResultPop (&ObjDesc, WalkState);
401 }
402
403 /* Check for error from the ACPICA core */
404
405 if (ACPI_FAILURE (Status))
406 {
407 AslCoreSubsystemError (Op, Status,
408 "Failure during constant evaluation", FALSE);
409 }
410 }
411
412 if (ACPI_FAILURE (Status))
413 {
414 /* We could not resolve the subtree for some reason */
415
416 AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op,
417 Op->Asl.ParseOpName);
418
419 /* Set the subtree value to ZERO anyway. Eliminates further errors */
420
421 OpcUpdateIntegerNode (Op, 0);
422 }
423 else
424 {
425 AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op,
426 Op->Asl.ParseOpName);
427
428 /*
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.
431 */
432 switch (ObjDesc->Common.Type)
433 {
434 case ACPI_TYPE_INTEGER:
435
436 OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value);
437
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;
443
444 case ACPI_TYPE_STRING:
445
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;
450
451 DbgPrint (ASL_PARSE_OUTPUT,
452 "Constant expression reduced to (STRING) %s\n",
453 Op->Common.Value.String);
454
455 break;
456
457 case ACPI_TYPE_BUFFER:
458
459 Op->Asl.ParseOpcode = PARSEOP_BUFFER;
460 Op->Common.AmlOpcode = AML_BUFFER_OP;
461 Op->Asl.CompileFlags = NODE_AML_PACKAGE;
462 UtSetParseOpName (Op);
463
464 /* Child node is the buffer length */
465
466 RootOp = TrAllocateNode (PARSEOP_INTEGER);
467
468 RootOp->Asl.AmlOpcode = AML_DWORD_OP;
469 RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length;
470 RootOp->Asl.Parent = Op;
471
472 (void) OpcSetOptimalIntegerSize (RootOp);
473
474 Op->Asl.Child = RootOp;
475 Op = RootOp;
476 UtSetParseOpName (Op);
477
478 /* Peer to the child is the raw buffer data */
479
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;
485
486 Op->Asl.Next = RootOp;
487 Op = RootOp;
488
489 DbgPrint (ASL_PARSE_OUTPUT,
490 "Constant expression reduced to (BUFFER) length %X\n",
491 ObjDesc->Buffer.Length);
492 break;
493
494 default:
495
496 printf ("Unsupported return type: %s\n",
497 AcpiUtGetObjectTypeName (ObjDesc));
498 break;
499 }
500 }
501
502 UtSetParseOpName (Op);
503 Op->Asl.Child = NULL;
504
505 AcpiDsDeleteWalkState (WalkState);
506 return (AE_CTRL_DEPTH);
507 }
508
509
510 /*******************************************************************************
511 *
512 * FUNCTION: OpcUpdateIntegerNode
513 *
514 * PARAMETERS: Op - Current parse object
515 *
516 * RETURN: None
517 *
518 * DESCRIPTION: Update node to the correct integer type.
519 *
520 ******************************************************************************/
521
522 static void
523 OpcUpdateIntegerNode (
524 ACPI_PARSE_OBJECT *Op,
525 UINT64 Value)
526 {
527
528 Op->Common.Value.Integer = Value;
529
530 /*
531 * The AmlLength is used by the parser to indicate a constant,
532 * (if non-zero). Length is either (1/2/4/8)
533 */
534 switch (Op->Asl.AmlLength)
535 {
536 case 1:
537
538 TrUpdateNode (PARSEOP_BYTECONST, Op);
539 Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
540 break;
541
542 case 2:
543
544 TrUpdateNode (PARSEOP_WORDCONST, Op);
545 Op->Asl.AmlOpcode = AML_RAW_DATA_WORD;
546 break;
547
548 case 4:
549
550 TrUpdateNode (PARSEOP_DWORDCONST, Op);
551 Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD;
552 break;
553
554 case 8:
555
556 TrUpdateNode (PARSEOP_QWORDCONST, Op);
557 Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD;
558 break;
559
560 case 0:
561 default:
562
563 OpcSetOptimalIntegerSize (Op);
564 TrUpdateNode (PARSEOP_INTEGER, Op);
565 break;
566 }
567
568 Op->Asl.AmlLength = 0;
569 }
570