asltree.c revision 1.1.1.6 1 /******************************************************************************
2 *
3 * Module Name: asltree - parse tree management
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2016, 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 "acapps.h"
47 #include <time.h>
48
49 #define _COMPONENT ACPI_COMPILER
50 ACPI_MODULE_NAME ("asltree")
51
52 /* Local prototypes */
53
54 static ACPI_PARSE_OBJECT *
55 TrGetNextNode (
56 void);
57
58
59 /*******************************************************************************
60 *
61 * FUNCTION: TrGetNextNode
62 *
63 * PARAMETERS: None
64 *
65 * RETURN: New parse node. Aborts on allocation failure
66 *
67 * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local
68 * dynamic memory manager for performance reasons (This has a
69 * major impact on the speed of the compiler.)
70 *
71 ******************************************************************************/
72
73 static ACPI_PARSE_OBJECT *
74 TrGetNextNode (
75 void)
76 {
77 ASL_CACHE_INFO *Cache;
78
79
80 if (Gbl_ParseOpCacheNext >= Gbl_ParseOpCacheLast)
81 {
82 /* Allocate a new buffer */
83
84 Cache = UtLocalCalloc (sizeof (Cache->Next) +
85 (sizeof (ACPI_PARSE_OBJECT) * ASL_PARSEOP_CACHE_SIZE));
86
87 /* Link new cache buffer to head of list */
88
89 Cache->Next = Gbl_ParseOpCacheList;
90 Gbl_ParseOpCacheList = Cache;
91
92 /* Setup cache management pointers */
93
94 Gbl_ParseOpCacheNext = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, Cache->Buffer);
95 Gbl_ParseOpCacheLast = Gbl_ParseOpCacheNext + ASL_PARSEOP_CACHE_SIZE;
96 }
97
98 Gbl_ParseOpCount++;
99 return (Gbl_ParseOpCacheNext++);
100 }
101
102
103 /*******************************************************************************
104 *
105 * FUNCTION: TrAllocateNode
106 *
107 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node
108 *
109 * RETURN: New parse node. Aborts on allocation failure
110 *
111 * DESCRIPTION: Allocate and initialize a new parse node for the parse tree
112 *
113 ******************************************************************************/
114
115 ACPI_PARSE_OBJECT *
116 TrAllocateNode (
117 UINT32 ParseOpcode)
118 {
119 ACPI_PARSE_OBJECT *Op;
120
121
122 Op = TrGetNextNode ();
123
124 Op->Asl.ParseOpcode = (UINT16) ParseOpcode;
125 Op->Asl.Filename = Gbl_Files[ASL_FILE_INPUT].Filename;
126 Op->Asl.LineNumber = Gbl_CurrentLineNumber;
127 Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber;
128 Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset;
129 Op->Asl.Column = Gbl_CurrentColumn;
130
131 UtSetParseOpName (Op);
132 return (Op);
133 }
134
135
136 /*******************************************************************************
137 *
138 * FUNCTION: TrReleaseNode
139 *
140 * PARAMETERS: Op - Op to be released
141 *
142 * RETURN: None
143 *
144 * DESCRIPTION: "release" a node. In truth, nothing is done since the node
145 * is part of a larger buffer
146 *
147 ******************************************************************************/
148
149 void
150 TrReleaseNode (
151 ACPI_PARSE_OBJECT *Op)
152 {
153
154 return;
155 }
156
157
158 /*******************************************************************************
159 *
160 * FUNCTION: TrSetCurrentFilename
161 *
162 * PARAMETERS: Op - An existing parse node
163 *
164 * RETURN: None
165 *
166 * DESCRIPTION: Save the include file filename. Used for debug output only.
167 *
168 ******************************************************************************/
169
170 void
171 TrSetCurrentFilename (
172 ACPI_PARSE_OBJECT *Op)
173 {
174 Op->Asl.Filename = Gbl_PreviousIncludeFilename;
175 }
176
177
178 /*******************************************************************************
179 *
180 * FUNCTION: TrUpdateNode
181 *
182 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node
183 * Op - An existing parse node
184 *
185 * RETURN: The updated node
186 *
187 * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to
188 * change an opcode to DEFAULT_ARG so that the node is ignored
189 * during the code generation. Also used to set generic integers
190 * to a specific size (8, 16, 32, or 64 bits)
191 *
192 ******************************************************************************/
193
194 ACPI_PARSE_OBJECT *
195 TrUpdateNode (
196 UINT32 ParseOpcode,
197 ACPI_PARSE_OBJECT *Op)
198 {
199
200 if (!Op)
201 {
202 return (NULL);
203 }
204
205 DbgPrint (ASL_PARSE_OUTPUT,
206 "\nUpdateNode: Old - %s, New - %s\n",
207 UtGetOpName (Op->Asl.ParseOpcode),
208 UtGetOpName (ParseOpcode));
209
210 /* Assign new opcode and name */
211
212 if (Op->Asl.ParseOpcode == PARSEOP_ONES)
213 {
214 switch (ParseOpcode)
215 {
216 case PARSEOP_BYTECONST:
217
218 Op->Asl.Value.Integer = ACPI_UINT8_MAX;
219 break;
220
221 case PARSEOP_WORDCONST:
222
223 Op->Asl.Value.Integer = ACPI_UINT16_MAX;
224 break;
225
226 case PARSEOP_DWORDCONST:
227
228 Op->Asl.Value.Integer = ACPI_UINT32_MAX;
229 break;
230
231 /* Don't need to do the QWORD case */
232
233 default:
234
235 /* Don't care about others */
236 break;
237 }
238 }
239
240 Op->Asl.ParseOpcode = (UINT16) ParseOpcode;
241 UtSetParseOpName (Op);
242
243 /*
244 * For the BYTE, WORD, and DWORD constants, make sure that the integer
245 * that was passed in will actually fit into the data type
246 */
247 switch (ParseOpcode)
248 {
249 case PARSEOP_BYTECONST:
250
251 UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX);
252 Op->Asl.Value.Integer &= ACPI_UINT8_MAX;
253 break;
254
255 case PARSEOP_WORDCONST:
256
257 UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX);
258 Op->Asl.Value.Integer &= ACPI_UINT16_MAX;
259 break;
260
261 case PARSEOP_DWORDCONST:
262
263 UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX);
264 Op->Asl.Value.Integer &= ACPI_UINT32_MAX;
265 break;
266
267 default:
268
269 /* Don't care about others, don't need to check QWORD */
270
271 break;
272 }
273
274 return (Op);
275 }
276
277
278 /*******************************************************************************
279 *
280 * FUNCTION: TrPrintNodeCompileFlags
281 *
282 * PARAMETERS: Flags - Flags word to be decoded
283 *
284 * RETURN: None
285 *
286 * DESCRIPTION: Decode a flags word to text. Displays all flags that are set.
287 *
288 ******************************************************************************/
289
290 void
291 TrPrintNodeCompileFlags (
292 UINT32 Flags)
293 {
294 UINT32 i;
295 UINT32 FlagBit = 1;
296 char *FlagName = NULL;
297
298
299 for (i = 0; i < 32; i++)
300 {
301 switch (Flags & FlagBit)
302 {
303 case NODE_VISITED:
304
305 FlagName = "NODE_VISITED";
306 break;
307
308 case NODE_AML_PACKAGE:
309
310 FlagName = "NODE_AML_PACKAGE";
311 break;
312
313 case NODE_IS_TARGET:
314
315 FlagName = "NODE_IS_TARGET";
316 break;
317
318 case NODE_IS_RESOURCE_DESC:
319
320 FlagName = "NODE_IS_RESOURCE_DESC";
321 break;
322
323 case NODE_IS_RESOURCE_FIELD:
324
325 FlagName = "NODE_IS_RESOURCE_FIELD";
326 break;
327
328 case NODE_HAS_NO_EXIT:
329
330 FlagName = "NODE_HAS_NO_EXIT";
331 break;
332
333 case NODE_IF_HAS_NO_EXIT:
334
335 FlagName = "NODE_IF_HAS_NO_EXIT";
336 break;
337
338 case NODE_NAME_INTERNALIZED:
339
340 FlagName = "NODE_NAME_INTERNALIZED";
341 break;
342
343 case NODE_METHOD_NO_RETVAL:
344
345 FlagName = "NODE_METHOD_NO_RETVAL";
346 break;
347
348 case NODE_METHOD_SOME_NO_RETVAL:
349
350 FlagName = "NODE_METHOD_SOME_NO_RETVAL";
351 break;
352
353 case NODE_RESULT_NOT_USED:
354
355 FlagName = "NODE_RESULT_NOT_USED";
356 break;
357
358 case NODE_METHOD_TYPED:
359
360 FlagName = "NODE_METHOD_TYPED";
361 break;
362
363 case NODE_COULD_NOT_REDUCE:
364
365 FlagName = "NODE_COULD_NOT_REDUCE";
366 break;
367
368 case NODE_COMPILE_TIME_CONST:
369
370 FlagName = "NODE_COMPILE_TIME_CONST";
371 break;
372
373 case NODE_IS_TERM_ARG:
374
375 FlagName = "NODE_IS_TERM_ARG";
376 break;
377
378 case NODE_WAS_ONES_OP:
379
380 FlagName = "NODE_WAS_ONES_OP";
381 break;
382
383 case NODE_IS_NAME_DECLARATION:
384
385 FlagName = "NODE_IS_NAME_DECLARATION";
386 break;
387
388 case NODE_COMPILER_EMITTED:
389
390 FlagName = "NODE_COMPILER_EMITTED";
391 break;
392
393 case NODE_IS_DUPLICATE:
394
395 FlagName = "NODE_IS_DUPLICATE";
396 break;
397
398 case NODE_IS_RESOURCE_DATA:
399
400 FlagName = "NODE_IS_RESOURCE_DATA";
401 break;
402
403 case NODE_IS_NULL_RETURN:
404
405 FlagName = "NODE_IS_NULL_RETURN";
406 break;
407
408 default:
409 break;
410 }
411
412 if (FlagName)
413 {
414 DbgPrint (ASL_PARSE_OUTPUT, " %s", FlagName);
415 FlagName = NULL;
416 }
417
418 FlagBit <<= 1;
419 }
420 }
421
422
423 /*******************************************************************************
424 *
425 * FUNCTION: TrSetNodeFlags
426 *
427 * PARAMETERS: Op - An existing parse node
428 * Flags - New flags word
429 *
430 * RETURN: The updated parser op
431 *
432 * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set
433 *
434 ******************************************************************************/
435
436 ACPI_PARSE_OBJECT *
437 TrSetNodeFlags (
438 ACPI_PARSE_OBJECT *Op,
439 UINT32 Flags)
440 {
441
442 if (!Op)
443 {
444 return (NULL);
445 }
446
447 DbgPrint (ASL_PARSE_OUTPUT,
448 "\nSetNodeFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags);
449
450 TrPrintNodeCompileFlags (Flags);
451 DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
452
453 Op->Asl.CompileFlags |= Flags;
454 return (Op);
455 }
456
457
458 /*******************************************************************************
459 *
460 * FUNCTION: TrSetNodeAmlLength
461 *
462 * PARAMETERS: Op - An existing parse node
463 * Length - AML Length
464 *
465 * RETURN: The updated parser op
466 *
467 * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate
468 * the presence of a node that must be reduced to a fixed length
469 * constant.
470 *
471 ******************************************************************************/
472
473 ACPI_PARSE_OBJECT *
474 TrSetNodeAmlLength (
475 ACPI_PARSE_OBJECT *Op,
476 UINT32 Length)
477 {
478
479 DbgPrint (ASL_PARSE_OUTPUT,
480 "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length);
481
482 if (!Op)
483 {
484 return (NULL);
485 }
486
487 Op->Asl.AmlLength = Length;
488 return (Op);
489 }
490
491
492 /*******************************************************************************
493 *
494 * FUNCTION: TrSetEndLineNumber
495 *
496 * PARAMETERS: Op - An existing parse node
497 *
498 * RETURN: None.
499 *
500 * DESCRIPTION: Set the ending line numbers (file line and logical line) of a
501 * parse node to the current line numbers.
502 *
503 ******************************************************************************/
504
505 void
506 TrSetEndLineNumber (
507 ACPI_PARSE_OBJECT *Op)
508 {
509
510 /* If the end line # is already set, just return */
511
512 if (Op->Asl.EndLine)
513 {
514 return;
515 }
516
517 Op->Asl.EndLine = Gbl_CurrentLineNumber;
518 Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber;
519 }
520
521
522 /*******************************************************************************
523 *
524 * FUNCTION: TrCreateAssignmentNode
525 *
526 * PARAMETERS: Target - Assignment target
527 * Source - Assignment source
528 *
529 * RETURN: Pointer to the new node. Aborts on allocation failure
530 *
531 * DESCRIPTION: Implements the C-style '=' operator. It changes the parse
532 * tree if possible to utilize the last argument of the math
533 * operators which is a target operand -- thus saving invocation
534 * of and additional Store() operator. An optimization.
535 *
536 ******************************************************************************/
537
538 ACPI_PARSE_OBJECT *
539 TrCreateAssignmentNode (
540 ACPI_PARSE_OBJECT *Target,
541 ACPI_PARSE_OBJECT *Source)
542 {
543 ACPI_PARSE_OBJECT *TargetOp;
544 ACPI_PARSE_OBJECT *SourceOp1;
545 ACPI_PARSE_OBJECT *SourceOp2;
546 ACPI_PARSE_OBJECT *Operator;
547
548
549 DbgPrint (ASL_PARSE_OUTPUT,
550 "\nTrCreateAssignmentNode Line [%u to %u] Source %s Target %s\n",
551 Source->Asl.LineNumber, Source->Asl.EndLine,
552 UtGetOpName (Source->Asl.ParseOpcode),
553 UtGetOpName (Target->Asl.ParseOpcode));
554
555 TrSetNodeFlags (Target, NODE_IS_TARGET);
556
557 switch (Source->Asl.ParseOpcode)
558 {
559 /*
560 * Only these operators can be optimized because they have
561 * a target operand
562 */
563 case PARSEOP_ADD:
564 case PARSEOP_AND:
565 case PARSEOP_DIVIDE:
566 case PARSEOP_INDEX:
567 case PARSEOP_MOD:
568 case PARSEOP_MULTIPLY:
569 case PARSEOP_NOT:
570 case PARSEOP_OR:
571 case PARSEOP_SHIFTLEFT:
572 case PARSEOP_SHIFTRIGHT:
573 case PARSEOP_SUBTRACT:
574 case PARSEOP_XOR:
575
576 break;
577
578 /* Otherwise, just create a normal Store operator */
579
580 default:
581
582 goto CannotOptimize;
583 }
584
585 /*
586 * Transform the parse tree such that the target is moved to the
587 * last operand of the operator
588 */
589 SourceOp1 = Source->Asl.Child;
590 SourceOp2 = SourceOp1->Asl.Next;
591
592 /* NOT only has one operand, but has a target */
593
594 if (Source->Asl.ParseOpcode == PARSEOP_NOT)
595 {
596 SourceOp2 = SourceOp1;
597 }
598
599 /* DIVIDE has an extra target operand (remainder) */
600
601 if (Source->Asl.ParseOpcode == PARSEOP_DIVIDE)
602 {
603 SourceOp2 = SourceOp2->Asl.Next;
604 }
605
606 TargetOp = SourceOp2->Asl.Next;
607
608 /*
609 * Can't perform this optimization if there already is a target
610 * for the operator (ZERO is a "no target" placeholder).
611 */
612 if (TargetOp->Asl.ParseOpcode != PARSEOP_ZERO)
613 {
614 goto CannotOptimize;
615 }
616
617 /* Link in the target as the final operand */
618
619 SourceOp2->Asl.Next = Target;
620 Target->Asl.Parent = Source;
621
622 return (Source);
623
624
625 CannotOptimize:
626
627 Operator = TrAllocateNode (PARSEOP_STORE);
628 TrLinkChildren (Operator, 2, Source, Target);
629
630 /* Set the appropriate line numbers for the new node */
631
632 Operator->Asl.LineNumber = Target->Asl.LineNumber;
633 Operator->Asl.LogicalLineNumber = Target->Asl.LogicalLineNumber;
634 Operator->Asl.LogicalByteOffset = Target->Asl.LogicalByteOffset;
635 Operator->Asl.Column = Target->Asl.Column;
636
637 return (Operator);
638 }
639
640
641 /*******************************************************************************
642 *
643 * FUNCTION: TrCreateLeafNode
644 *
645 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node
646 *
647 * RETURN: Pointer to the new node. Aborts on allocation failure
648 *
649 * DESCRIPTION: Create a simple leaf node (no children or peers, and no value
650 * assigned to the node)
651 *
652 ******************************************************************************/
653
654 ACPI_PARSE_OBJECT *
655 TrCreateLeafNode (
656 UINT32 ParseOpcode)
657 {
658 ACPI_PARSE_OBJECT *Op;
659
660
661 Op = TrAllocateNode (ParseOpcode);
662
663 DbgPrint (ASL_PARSE_OUTPUT,
664 "\nCreateLeafNode Ln/Col %u/%u NewNode %p Op %s\n\n",
665 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode));
666
667 return (Op);
668 }
669
670
671 /*******************************************************************************
672 *
673 * FUNCTION: TrCreateNullTarget
674 *
675 * PARAMETERS: None
676 *
677 * RETURN: Pointer to the new node. Aborts on allocation failure
678 *
679 * DESCRIPTION: Create a "null" target node. This is defined by the ACPI
680 * specification to be a zero AML opcode, and indicates that
681 * no target has been specified for the parent operation
682 *
683 ******************************************************************************/
684
685 ACPI_PARSE_OBJECT *
686 TrCreateNullTarget (
687 void)
688 {
689 ACPI_PARSE_OBJECT *Op;
690
691
692 Op = TrAllocateNode (PARSEOP_ZERO);
693 Op->Asl.CompileFlags |= (NODE_IS_TARGET | NODE_COMPILE_TIME_CONST);
694
695 DbgPrint (ASL_PARSE_OUTPUT,
696 "\nCreateNullTarget Ln/Col %u/%u NewNode %p Op %s\n",
697 Op->Asl.LineNumber, Op->Asl.Column, Op,
698 UtGetOpName (Op->Asl.ParseOpcode));
699
700 return (Op);
701 }
702
703
704 /*******************************************************************************
705 *
706 * FUNCTION: TrCreateConstantLeafNode
707 *
708 * PARAMETERS: ParseOpcode - The constant opcode
709 *
710 * RETURN: Pointer to the new node. Aborts on allocation failure
711 *
712 * DESCRIPTION: Create a leaf node (no children or peers) for one of the
713 * special constants - __LINE__, __FILE__, and __DATE__.
714 *
715 * Note: An implemenation of __FUNC__ cannot happen here because we don't
716 * have a full parse tree at this time and cannot find the parent control
717 * method. If it is ever needed, __FUNC__ must be implemented later, after
718 * the parse tree has been fully constructed.
719 *
720 ******************************************************************************/
721
722 ACPI_PARSE_OBJECT *
723 TrCreateConstantLeafNode (
724 UINT32 ParseOpcode)
725 {
726 ACPI_PARSE_OBJECT *Op = NULL;
727 time_t CurrentTime;
728 char *StaticTimeString;
729 char *TimeString;
730 char *Filename;
731
732
733 switch (ParseOpcode)
734 {
735 case PARSEOP___LINE__:
736
737 Op = TrAllocateNode (PARSEOP_INTEGER);
738 Op->Asl.Value.Integer = Op->Asl.LineNumber;
739 break;
740
741 case PARSEOP___PATH__:
742
743 Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
744
745 /* Op.Asl.Filename contains the full pathname to the file */
746
747 Op->Asl.Value.String = Op->Asl.Filename;
748 break;
749
750 case PARSEOP___FILE__:
751
752 Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
753
754 /* Get the simple filename from the full path */
755
756 FlSplitInputPathname (Op->Asl.Filename, NULL, &Filename);
757 Op->Asl.Value.String = Filename;
758 break;
759
760 case PARSEOP___DATE__:
761
762 Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
763
764 /* Get a copy of the current time */
765
766 CurrentTime = time (NULL);
767 StaticTimeString = ctime (&CurrentTime);
768 TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1);
769 strcpy (TimeString, StaticTimeString);
770
771 TimeString[strlen(TimeString) -1] = 0; /* Remove trailing newline */
772 Op->Asl.Value.String = TimeString;
773 break;
774
775 default: /* This would be an internal error */
776
777 return (NULL);
778 }
779
780 DbgPrint (ASL_PARSE_OUTPUT,
781 "\nCreateConstantLeafNode Ln/Col %u/%u NewNode %p "
782 "Op %s Value %8.8X%8.8X \n",
783 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode),
784 ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer));
785 return (Op);
786 }
787
788
789 /*******************************************************************************
790 *
791 * FUNCTION: TrCreateTargetOperand
792 *
793 * PARAMETERS: OriginalOp - Op to be copied
794 *
795 * RETURN: Pointer to the new node. Aborts on allocation failure
796 *
797 * DESCRIPTION: Copy an existing node (and subtree). Used in ASL+ (C-style)
798 * expressions where the target is the same as one of the
799 * operands. A new node and subtree must be created from the
800 * original so that the parse tree can be linked properly.
801 *
802 * NOTE: This code is specific to target operands that are the last
803 * operand in an ASL/AML operator. Meaning that the top-level
804 * parse Op in a possible subtree has a NULL Next pointer.
805 * This simplifies the recursion.
806 *
807 * Subtree example:
808 * DeRefOf (Local1) += 32
809 *
810 * This gets converted to:
811 * Add (DeRefOf (Local1), 32, DeRefOf (Local1))
812 *
813 * Each DeRefOf has a single child, Local1. Even more complex
814 * subtrees can be created via the Index and DeRefOf operators.
815 *
816 ******************************************************************************/
817
818 ACPI_PARSE_OBJECT *
819 TrCreateTargetOperand (
820 ACPI_PARSE_OBJECT *OriginalOp,
821 ACPI_PARSE_OBJECT *ParentOp)
822 {
823 ACPI_PARSE_OBJECT *Op;
824
825
826 if (!OriginalOp)
827 {
828 return (NULL);
829 }
830
831 Op = TrGetNextNode ();
832
833 /* Copy the pertinent values (omit link pointer fields) */
834
835 Op->Asl.Value = OriginalOp->Asl.Value;
836 Op->Asl.Filename = OriginalOp->Asl.Filename;
837 Op->Asl.LineNumber = OriginalOp->Asl.LineNumber;
838 Op->Asl.LogicalLineNumber = OriginalOp->Asl.LogicalLineNumber;
839 Op->Asl.LogicalByteOffset = OriginalOp->Asl.LogicalByteOffset;
840 Op->Asl.Column = OriginalOp->Asl.Column;
841 Op->Asl.Flags = OriginalOp->Asl.Flags;
842 Op->Asl.CompileFlags = OriginalOp->Asl.CompileFlags;
843 Op->Asl.AmlOpcode = OriginalOp->Asl.AmlOpcode;
844 Op->Asl.ParseOpcode = OriginalOp->Asl.ParseOpcode;
845 Op->Asl.Parent = ParentOp;
846 UtSetParseOpName (Op);
847
848 /* Copy a possible subtree below this node */
849
850 if (OriginalOp->Asl.Child)
851 {
852 Op->Asl.Child = TrCreateTargetOperand (OriginalOp->Asl.Child, Op);
853 }
854
855 if (OriginalOp->Asl.Next) /* Null for top-level node */
856 {
857 Op->Asl.Next = TrCreateTargetOperand (OriginalOp->Asl.Next, ParentOp);
858 }
859
860 return (Op);
861 }
862
863
864 /*******************************************************************************
865 *
866 * FUNCTION: TrCreateValuedLeafNode
867 *
868 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node
869 * Value - Value to be assigned to the node
870 *
871 * RETURN: Pointer to the new node. Aborts on allocation failure
872 *
873 * DESCRIPTION: Create a leaf node (no children or peers) with a value
874 * assigned to it
875 *
876 ******************************************************************************/
877
878 ACPI_PARSE_OBJECT *
879 TrCreateValuedLeafNode (
880 UINT32 ParseOpcode,
881 UINT64 Value)
882 {
883 ACPI_PARSE_OBJECT *Op;
884
885
886 Op = TrAllocateNode (ParseOpcode);
887
888 DbgPrint (ASL_PARSE_OUTPUT,
889 "\nCreateValuedLeafNode Ln/Col %u/%u NewNode %p "
890 "Op %s Value %8.8X%8.8X ",
891 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode),
892 ACPI_FORMAT_UINT64 (Value));
893 Op->Asl.Value.Integer = Value;
894
895 switch (ParseOpcode)
896 {
897 case PARSEOP_STRING_LITERAL:
898
899 DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value);
900 break;
901
902 case PARSEOP_NAMESEG:
903
904 DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value);
905 break;
906
907 case PARSEOP_NAMESTRING:
908
909 DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value);
910 break;
911
912 case PARSEOP_EISAID:
913
914 DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value);
915 break;
916
917 case PARSEOP_METHOD:
918
919 DbgPrint (ASL_PARSE_OUTPUT, "METHOD");
920 break;
921
922 case PARSEOP_INTEGER:
923
924 DbgPrint (ASL_PARSE_OUTPUT, "INTEGER->%8.8X%8.8X",
925 ACPI_FORMAT_UINT64 (Value));
926 break;
927
928 default:
929
930 break;
931 }
932
933 DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
934 return (Op);
935 }
936
937
938 /*******************************************************************************
939 *
940 * FUNCTION: TrCreateNode
941 *
942 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node
943 * NumChildren - Number of children to follow
944 * ... - A list of child nodes to link to the new
945 * node. NumChildren long.
946 *
947 * RETURN: Pointer to the new node. Aborts on allocation failure
948 *
949 * DESCRIPTION: Create a new parse node and link together a list of child
950 * nodes underneath the new node.
951 *
952 ******************************************************************************/
953
954 ACPI_PARSE_OBJECT *
955 TrCreateNode (
956 UINT32 ParseOpcode,
957 UINT32 NumChildren,
958 ...)
959 {
960 ACPI_PARSE_OBJECT *Op;
961 ACPI_PARSE_OBJECT *Child;
962 ACPI_PARSE_OBJECT *PrevChild;
963 va_list ap;
964 UINT32 i;
965 BOOLEAN FirstChild;
966
967
968 va_start (ap, NumChildren);
969
970 /* Allocate one new node */
971
972 Op = TrAllocateNode (ParseOpcode);
973
974 DbgPrint (ASL_PARSE_OUTPUT,
975 "\nCreateNode Ln/Col %u/%u NewParent %p Child %u Op %s ",
976 Op->Asl.LineNumber, Op->Asl.Column, Op,
977 NumChildren, UtGetOpName(ParseOpcode));
978
979 /* Some extra debug output based on the parse opcode */
980
981 switch (ParseOpcode)
982 {
983 case PARSEOP_ASL_CODE:
984
985 RootNode = Op;
986 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
987 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
988 break;
989
990 case PARSEOP_DEFINITION_BLOCK:
991
992 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
993 break;
994
995 case PARSEOP_OPERATIONREGION:
996
997 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
998 break;
999
1000 case PARSEOP_OR:
1001
1002 DbgPrint (ASL_PARSE_OUTPUT, "OR->");
1003 break;
1004
1005 default:
1006
1007 /* Nothing to do for other opcodes */
1008
1009 break;
1010 }
1011
1012 /* Link the new node to its children */
1013
1014 PrevChild = NULL;
1015 FirstChild = TRUE;
1016 for (i = 0; i < NumChildren; i++)
1017 {
1018 /* Get the next child */
1019
1020 Child = va_arg (ap, ACPI_PARSE_OBJECT *);
1021 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
1022
1023 /*
1024 * If child is NULL, this means that an optional argument
1025 * was omitted. We must create a placeholder with a special
1026 * opcode (DEFAULT_ARG) so that the code generator will know
1027 * that it must emit the correct default for this argument
1028 */
1029 if (!Child)
1030 {
1031 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
1032 }
1033
1034 /* Link first child to parent */
1035
1036 if (FirstChild)
1037 {
1038 FirstChild = FALSE;
1039 Op->Asl.Child = Child;
1040 }
1041
1042 /* Point all children to parent */
1043
1044 Child->Asl.Parent = Op;
1045
1046 /* Link children in a peer list */
1047
1048 if (PrevChild)
1049 {
1050 PrevChild->Asl.Next = Child;
1051 };
1052
1053 /*
1054 * This child might be a list, point all nodes in the list
1055 * to the same parent
1056 */
1057 while (Child->Asl.Next)
1058 {
1059 Child = Child->Asl.Next;
1060 Child->Asl.Parent = Op;
1061 }
1062
1063 PrevChild = Child;
1064 }
1065 va_end(ap);
1066
1067 DbgPrint (ASL_PARSE_OUTPUT, "\n");
1068 return (Op);
1069 }
1070
1071
1072 /*******************************************************************************
1073 *
1074 * FUNCTION: TrLinkChildren
1075 *
1076 * PARAMETERS: Op - An existing parse node
1077 * NumChildren - Number of children to follow
1078 * ... - A list of child nodes to link to the new
1079 * node. NumChildren long.
1080 *
1081 * RETURN: The updated (linked) node
1082 *
1083 * DESCRIPTION: Link a group of nodes to an existing parse node
1084 *
1085 ******************************************************************************/
1086
1087 ACPI_PARSE_OBJECT *
1088 TrLinkChildren (
1089 ACPI_PARSE_OBJECT *Op,
1090 UINT32 NumChildren,
1091 ...)
1092 {
1093 ACPI_PARSE_OBJECT *Child;
1094 ACPI_PARSE_OBJECT *PrevChild;
1095 va_list ap;
1096 UINT32 i;
1097 BOOLEAN FirstChild;
1098
1099
1100 va_start (ap, NumChildren);
1101
1102
1103 TrSetEndLineNumber (Op);
1104
1105 DbgPrint (ASL_PARSE_OUTPUT,
1106 "\nLinkChildren Line [%u to %u] NewParent %p Child %u Op %s ",
1107 Op->Asl.LineNumber, Op->Asl.EndLine,
1108 Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode));
1109
1110 switch (Op->Asl.ParseOpcode)
1111 {
1112 case PARSEOP_ASL_CODE:
1113
1114 RootNode = Op;
1115 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
1116 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
1117 break;
1118
1119 case PARSEOP_DEFINITION_BLOCK:
1120
1121 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
1122 break;
1123
1124 case PARSEOP_OPERATIONREGION:
1125
1126 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
1127 break;
1128
1129 case PARSEOP_OR:
1130
1131 DbgPrint (ASL_PARSE_OUTPUT, "OR->");
1132 break;
1133
1134 default:
1135
1136 /* Nothing to do for other opcodes */
1137
1138 break;
1139 }
1140
1141 /* Link the new node to it's children */
1142
1143 PrevChild = NULL;
1144 FirstChild = TRUE;
1145 for (i = 0; i < NumChildren; i++)
1146 {
1147 Child = va_arg (ap, ACPI_PARSE_OBJECT *);
1148
1149 if ((Child == PrevChild) && (Child != NULL))
1150 {
1151 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child,
1152 "Child node list invalid");
1153 va_end(ap);
1154 return (Op);
1155 }
1156
1157 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
1158
1159 /*
1160 * If child is NULL, this means that an optional argument
1161 * was omitted. We must create a placeholder with a special
1162 * opcode (DEFAULT_ARG) so that the code generator will know
1163 * that it must emit the correct default for this argument
1164 */
1165 if (!Child)
1166 {
1167 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
1168 }
1169
1170 /* Link first child to parent */
1171
1172 if (FirstChild)
1173 {
1174 FirstChild = FALSE;
1175 Op->Asl.Child = Child;
1176 }
1177
1178 /* Point all children to parent */
1179
1180 Child->Asl.Parent = Op;
1181
1182 /* Link children in a peer list */
1183
1184 if (PrevChild)
1185 {
1186 PrevChild->Asl.Next = Child;
1187 };
1188
1189 /*
1190 * This child might be a list, point all nodes in the list
1191 * to the same parent
1192 */
1193 while (Child->Asl.Next)
1194 {
1195 Child = Child->Asl.Next;
1196 Child->Asl.Parent = Op;
1197 }
1198
1199 PrevChild = Child;
1200 }
1201
1202 va_end(ap);
1203 DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
1204 return (Op);
1205 }
1206
1207
1208 /*******************************************************************************
1209 *
1210 * FUNCTION: TrLinkPeerNode
1211 *
1212 * PARAMETERS: Op1 - First peer
1213 * Op2 - Second peer
1214 *
1215 * RETURN: Op1 or the non-null node.
1216 *
1217 * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null.
1218 *
1219 ******************************************************************************/
1220
1221 ACPI_PARSE_OBJECT *
1222 TrLinkPeerNode (
1223 ACPI_PARSE_OBJECT *Op1,
1224 ACPI_PARSE_OBJECT *Op2)
1225 {
1226 ACPI_PARSE_OBJECT *Next;
1227
1228
1229 DbgPrint (ASL_PARSE_OUTPUT,
1230 "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n",
1231 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL,
1232 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL);
1233
1234
1235 if ((!Op1) && (!Op2))
1236 {
1237 DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n");
1238 return (Op1);
1239 }
1240
1241 /* If one of the nodes is null, just return the non-null node */
1242
1243 if (!Op2)
1244 {
1245 return (Op1);
1246 }
1247
1248 if (!Op1)
1249 {
1250 return (Op2);
1251 }
1252
1253 if (Op1 == Op2)
1254 {
1255 DbgPrint (ASL_DEBUG_OUTPUT,
1256 "\n************* Internal error, linking node to itself %p\n",
1257 Op1);
1258 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1,
1259 "Linking node to itself");
1260 return (Op1);
1261 }
1262
1263 Op1->Asl.Parent = Op2->Asl.Parent;
1264
1265 /*
1266 * Op 1 may already have a peer list (such as an IF/ELSE pair),
1267 * so we must walk to the end of the list and attach the new
1268 * peer at the end
1269 */
1270 Next = Op1;
1271 while (Next->Asl.Next)
1272 {
1273 Next = Next->Asl.Next;
1274 }
1275
1276 Next->Asl.Next = Op2;
1277 return (Op1);
1278 }
1279
1280
1281 /*******************************************************************************
1282 *
1283 * FUNCTION: TrLinkPeerNodes
1284 *
1285 * PARAMETERS: NumPeers - The number of nodes in the list to follow
1286 * ... - A list of nodes to link together as peers
1287 *
1288 * RETURN: The first node in the list (head of the peer list)
1289 *
1290 * DESCRIPTION: Link together an arbitrary number of peer nodes.
1291 *
1292 ******************************************************************************/
1293
1294 ACPI_PARSE_OBJECT *
1295 TrLinkPeerNodes (
1296 UINT32 NumPeers,
1297 ...)
1298 {
1299 ACPI_PARSE_OBJECT *This;
1300 ACPI_PARSE_OBJECT *Next;
1301 va_list ap;
1302 UINT32 i;
1303 ACPI_PARSE_OBJECT *Start;
1304
1305
1306 DbgPrint (ASL_PARSE_OUTPUT,
1307 "\nLinkPeerNodes: (%u) ", NumPeers);
1308
1309 va_start (ap, NumPeers);
1310 This = va_arg (ap, ACPI_PARSE_OBJECT *);
1311 Start = This;
1312
1313 /*
1314 * Link all peers
1315 */
1316 for (i = 0; i < (NumPeers -1); i++)
1317 {
1318 DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This);
1319
1320 while (This->Asl.Next)
1321 {
1322 This = This->Asl.Next;
1323 }
1324
1325 /* Get another peer node */
1326
1327 Next = va_arg (ap, ACPI_PARSE_OBJECT *);
1328 if (!Next)
1329 {
1330 Next = TrAllocateNode (PARSEOP_DEFAULT_ARG);
1331 }
1332
1333 /* link new node to the current node */
1334
1335 This->Asl.Next = Next;
1336 This = Next;
1337 }
1338 va_end (ap);
1339
1340 DbgPrint (ASL_PARSE_OUTPUT,"\n");
1341 return (Start);
1342 }
1343
1344
1345 /*******************************************************************************
1346 *
1347 * FUNCTION: TrLinkChildNode
1348 *
1349 * PARAMETERS: Op1 - Parent node
1350 * Op2 - Op to become a child
1351 *
1352 * RETURN: The parent node
1353 *
1354 * DESCRIPTION: Link two nodes together as a parent and child
1355 *
1356 ******************************************************************************/
1357
1358 ACPI_PARSE_OBJECT *
1359 TrLinkChildNode (
1360 ACPI_PARSE_OBJECT *Op1,
1361 ACPI_PARSE_OBJECT *Op2)
1362 {
1363 ACPI_PARSE_OBJECT *Next;
1364
1365
1366 DbgPrint (ASL_PARSE_OUTPUT,
1367 "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n",
1368 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL,
1369 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL);
1370
1371 if (!Op1 || !Op2)
1372 {
1373 return (Op1);
1374 }
1375
1376 Op1->Asl.Child = Op2;
1377
1378 /* Set the child and all peers of the child to point to the parent */
1379
1380 Next = Op2;
1381 while (Next)
1382 {
1383 Next->Asl.Parent = Op1;
1384 Next = Next->Asl.Next;
1385 }
1386
1387 return (Op1);
1388 }
1389
1390
1391 /*******************************************************************************
1392 *
1393 * FUNCTION: TrWalkParseTree
1394 *
1395 * PARAMETERS: Visitation - Type of walk
1396 * DescendingCallback - Called during tree descent
1397 * AscendingCallback - Called during tree ascent
1398 * Context - To be passed to the callbacks
1399 *
1400 * RETURN: Status from callback(s)
1401 *
1402 * DESCRIPTION: Walk the entire parse tree.
1403 *
1404 ******************************************************************************/
1405
1406 ACPI_STATUS
1407 TrWalkParseTree (
1408 ACPI_PARSE_OBJECT *Op,
1409 UINT32 Visitation,
1410 ASL_WALK_CALLBACK DescendingCallback,
1411 ASL_WALK_CALLBACK AscendingCallback,
1412 void *Context)
1413 {
1414 UINT32 Level;
1415 BOOLEAN NodePreviouslyVisited;
1416 ACPI_PARSE_OBJECT *StartOp = Op;
1417 ACPI_STATUS Status;
1418
1419
1420 if (!RootNode)
1421 {
1422 return (AE_OK);
1423 }
1424
1425 Level = 0;
1426 NodePreviouslyVisited = FALSE;
1427
1428 switch (Visitation)
1429 {
1430 case ASL_WALK_VISIT_DOWNWARD:
1431
1432 while (Op)
1433 {
1434 if (!NodePreviouslyVisited)
1435 {
1436 /* Let the callback process the node. */
1437
1438 Status = DescendingCallback (Op, Level, Context);
1439 if (ACPI_SUCCESS (Status))
1440 {
1441 /* Visit children first, once */
1442
1443 if (Op->Asl.Child)
1444 {
1445 Level++;
1446 Op = Op->Asl.Child;
1447 continue;
1448 }
1449 }
1450 else if (Status != AE_CTRL_DEPTH)
1451 {
1452 /* Exit immediately on any error */
1453
1454 return (Status);
1455 }
1456 }
1457
1458 /* Terminate walk at start op */
1459
1460 if (Op == StartOp)
1461 {
1462 break;
1463 }
1464
1465 /* No more children, visit peers */
1466
1467 if (Op->Asl.Next)
1468 {
1469 Op = Op->Asl.Next;
1470 NodePreviouslyVisited = FALSE;
1471 }
1472 else
1473 {
1474 /* No children or peers, re-visit parent */
1475
1476 if (Level != 0 )
1477 {
1478 Level--;
1479 }
1480 Op = Op->Asl.Parent;
1481 NodePreviouslyVisited = TRUE;
1482 }
1483 }
1484 break;
1485
1486 case ASL_WALK_VISIT_UPWARD:
1487
1488 while (Op)
1489 {
1490 /* Visit leaf node (no children) or parent node on return trip */
1491
1492 if ((!Op->Asl.Child) ||
1493 (NodePreviouslyVisited))
1494 {
1495 /* Let the callback process the node. */
1496
1497 Status = AscendingCallback (Op, Level, Context);
1498 if (ACPI_FAILURE (Status))
1499 {
1500 return (Status);
1501 }
1502 }
1503 else
1504 {
1505 /* Visit children first, once */
1506
1507 Level++;
1508 Op = Op->Asl.Child;
1509 continue;
1510 }
1511
1512 /* Terminate walk at start op */
1513
1514 if (Op == StartOp)
1515 {
1516 break;
1517 }
1518
1519 /* No more children, visit peers */
1520
1521 if (Op->Asl.Next)
1522 {
1523 Op = Op->Asl.Next;
1524 NodePreviouslyVisited = FALSE;
1525 }
1526 else
1527 {
1528 /* No children or peers, re-visit parent */
1529
1530 if (Level != 0 )
1531 {
1532 Level--;
1533 }
1534 Op = Op->Asl.Parent;
1535 NodePreviouslyVisited = TRUE;
1536 }
1537 }
1538 break;
1539
1540 case ASL_WALK_VISIT_TWICE:
1541
1542 while (Op)
1543 {
1544 if (NodePreviouslyVisited)
1545 {
1546 Status = AscendingCallback (Op, Level, Context);
1547 if (ACPI_FAILURE (Status))
1548 {
1549 return (Status);
1550 }
1551 }
1552 else
1553 {
1554 /* Let the callback process the node. */
1555
1556 Status = DescendingCallback (Op, Level, Context);
1557 if (ACPI_SUCCESS (Status))
1558 {
1559 /* Visit children first, once */
1560
1561 if (Op->Asl.Child)
1562 {
1563 Level++;
1564 Op = Op->Asl.Child;
1565 continue;
1566 }
1567 }
1568 else if (Status != AE_CTRL_DEPTH)
1569 {
1570 /* Exit immediately on any error */
1571
1572 return (Status);
1573 }
1574 }
1575
1576 /* Terminate walk at start op */
1577
1578 if (Op == StartOp)
1579 {
1580 break;
1581 }
1582
1583 /* No more children, visit peers */
1584
1585 if (Op->Asl.Next)
1586 {
1587 Op = Op->Asl.Next;
1588 NodePreviouslyVisited = FALSE;
1589 }
1590 else
1591 {
1592 /* No children or peers, re-visit parent */
1593
1594 if (Level != 0 )
1595 {
1596 Level--;
1597 }
1598 Op = Op->Asl.Parent;
1599 NodePreviouslyVisited = TRUE;
1600 }
1601 }
1602 break;
1603
1604 default:
1605 /* No other types supported */
1606 break;
1607 }
1608
1609 /* If we get here, the walk completed with no errors */
1610
1611 return (AE_OK);
1612 }
1613