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