1 /******************************************************************************
3 * Module Name: asltransform - Parse tree transforms
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2013, 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.
45 #include "aslcompiler.h"
46 #include "aslcompiler.y.h"
48 #define _COMPONENT ACPI_COMPILER
49 ACPI_MODULE_NAME ("asltransform")
51 /* Local prototypes */
55 ACPI_PARSE_OBJECT
*Op
);
58 TrAmlGetNextTempName (
59 ACPI_PARSE_OBJECT
*Op
,
63 TrAmlInitLineNumbers (
64 ACPI_PARSE_OBJECT
*Op
,
65 ACPI_PARSE_OBJECT
*Neighbor
);
69 ACPI_PARSE_OBJECT
*Op
,
73 TrAmlSetSubtreeParent (
74 ACPI_PARSE_OBJECT
*Op
,
75 ACPI_PARSE_OBJECT
*Parent
);
79 ACPI_PARSE_OBJECT
*Op
,
80 ACPI_PARSE_OBJECT
*NewPeer
);
84 ACPI_PARSE_OBJECT
*Op
);
88 ACPI_PARSE_OBJECT
*StartNode
);
91 /*******************************************************************************
93 * FUNCTION: TrAmlGetNextTempName
95 * PARAMETERS: Op - Current parse op
96 * TempCount - Current temporary counter. Was originally
97 * per-module; Currently per method, could be
98 * expanded to per-scope.
100 * RETURN: A pointer to name (allocated here).
102 * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are
103 * reserved for use by the ASL compiler. (_T_0 through _T_Z)
105 ******************************************************************************/
108 TrAmlGetNextTempName (
109 ACPI_PARSE_OBJECT
*Op
,
115 if (*TempCount
>= (10+26)) /* 0-35 valid: 0-9 and A-Z for TempName[3] */
119 AslError (ASL_ERROR
, ASL_MSG_TOO_MANY_TEMPS
, Op
, NULL
);
123 TempName
= UtLocalCalloc (5);
125 if (*TempCount
< 10) /* 0-9 */
127 TempName
[3] = (char) (*TempCount
+ '0');
129 else /* 10-35: A-Z */
131 TempName
[3] = (char) (*TempCount
+ ('A' - 10));
135 /* First three characters are always "_T_" */
145 /*******************************************************************************
147 * FUNCTION: TrAmlInitLineNumbers
149 * PARAMETERS: Op - Op to be initialized
150 * Neighbor - Op used for initialization values
154 * DESCRIPTION: Initialized the various line numbers for a parse node.
156 ******************************************************************************/
159 TrAmlInitLineNumbers (
160 ACPI_PARSE_OBJECT
*Op
,
161 ACPI_PARSE_OBJECT
*Neighbor
)
164 Op
->Asl
.EndLine
= Neighbor
->Asl
.EndLine
;
165 Op
->Asl
.EndLogicalLine
= Neighbor
->Asl
.EndLogicalLine
;
166 Op
->Asl
.LineNumber
= Neighbor
->Asl
.LineNumber
;
167 Op
->Asl
.LogicalByteOffset
= Neighbor
->Asl
.LogicalByteOffset
;
168 Op
->Asl
.LogicalLineNumber
= Neighbor
->Asl
.LogicalLineNumber
;
172 /*******************************************************************************
174 * FUNCTION: TrAmlInitNode
176 * PARAMETERS: Op - Op to be initialized
177 * ParseOpcode - Opcode for this node
181 * DESCRIPTION: Initialize a node with the parse opcode and opcode name.
183 ******************************************************************************/
187 ACPI_PARSE_OBJECT
*Op
,
191 Op
->Asl
.ParseOpcode
= ParseOpcode
;
192 UtSetParseOpName (Op
);
196 /*******************************************************************************
198 * FUNCTION: TrAmlSetSubtreeParent
200 * PARAMETERS: Op - First node in a list of peer nodes
201 * Parent - Parent of the subtree
205 * DESCRIPTION: Set the parent for all peer nodes in a subtree
207 ******************************************************************************/
210 TrAmlSetSubtreeParent (
211 ACPI_PARSE_OBJECT
*Op
,
212 ACPI_PARSE_OBJECT
*Parent
)
214 ACPI_PARSE_OBJECT
*Next
;
220 Next
->Asl
.Parent
= Parent
;
221 Next
= Next
->Asl
.Next
;
226 /*******************************************************************************
228 * FUNCTION: TrAmlInsertPeer
230 * PARAMETERS: Op - First node in a list of peer nodes
231 * NewPeer - Peer node to insert
235 * DESCRIPTION: Insert a new peer node into a list of peers.
237 ******************************************************************************/
241 ACPI_PARSE_OBJECT
*Op
,
242 ACPI_PARSE_OBJECT
*NewPeer
)
245 NewPeer
->Asl
.Next
= Op
->Asl
.Next
;
246 Op
->Asl
.Next
= NewPeer
;
250 /*******************************************************************************
252 * FUNCTION: TrAmlTransformWalk
254 * PARAMETERS: ASL_WALK_CALLBACK
258 * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML
261 ******************************************************************************/
265 ACPI_PARSE_OBJECT
*Op
,
270 TrTransformSubtree (Op
);
275 /*******************************************************************************
277 * FUNCTION: TrTransformSubtree
279 * PARAMETERS: Op - The parent parse node
283 * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more
284 * complex AML opcodes require processing of the child nodes
285 * (arguments/operands).
287 ******************************************************************************/
291 ACPI_PARSE_OBJECT
*Op
)
294 if (Op
->Asl
.AmlOpcode
== AML_RAW_DATA_BYTE
)
299 switch (Op
->Asl
.ParseOpcode
)
301 case PARSEOP_DEFINITIONBLOCK
:
303 TrDoDefinitionBlock (Op
);
313 * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global,
321 /* Nothing to do here for other opcodes */
328 /*******************************************************************************
330 * FUNCTION: TrDoDefinitionBlock
332 * PARAMETERS: Op - Parse node
336 * DESCRIPTION: Find the end of the definition block and set a global to this
337 * node. It is used by the compiler to insert compiler-generated
338 * names at the root level of the namespace.
340 ******************************************************************************/
343 TrDoDefinitionBlock (
344 ACPI_PARSE_OBJECT
*Op
)
346 ACPI_PARSE_OBJECT
*Next
;
350 Next
= Op
->Asl
.Child
;
351 for (i
= 0; i
< 5; i
++)
353 Next
= Next
->Asl
.Next
;
357 * This is the table signature. Only the DSDT can be assumed
358 * to be at the root of the namespace; Therefore, namepath
359 * optimization can only be performed on the DSDT.
361 if (!ACPI_COMPARE_NAME (Next
->Asl
.Value
.String
, ACPI_SIG_DSDT
))
363 Gbl_ReferenceOptimizationFlag
= FALSE
;
368 Gbl_FirstLevelInsertionNode
= Next
;
372 /*******************************************************************************
374 * FUNCTION: TrDoSwitch
376 * PARAMETERS: StartNode - Parse node for SWITCH
381 * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is
382 * no actual AML opcode for SWITCH -- it must be simulated.
384 ******************************************************************************/
388 ACPI_PARSE_OBJECT
*StartNode
)
390 ACPI_PARSE_OBJECT
*Next
;
391 ACPI_PARSE_OBJECT
*CaseOp
= NULL
;
392 ACPI_PARSE_OBJECT
*CaseBlock
= NULL
;
393 ACPI_PARSE_OBJECT
*DefaultOp
= NULL
;
394 ACPI_PARSE_OBJECT
*CurrentParentNode
;
395 ACPI_PARSE_OBJECT
*Conditional
= NULL
;
396 ACPI_PARSE_OBJECT
*Predicate
;
397 ACPI_PARSE_OBJECT
*Peer
;
398 ACPI_PARSE_OBJECT
*NewOp
;
399 ACPI_PARSE_OBJECT
*NewOp2
;
400 ACPI_PARSE_OBJECT
*MethodOp
;
401 ACPI_PARSE_OBJECT
*StoreOp
;
402 ACPI_PARSE_OBJECT
*BreakOp
;
403 ACPI_PARSE_OBJECT
*BufferOp
;
404 char *PredicateValueName
;
409 /* Start node is the Switch() node */
411 CurrentParentNode
= StartNode
;
413 /* Create a new temp name of the form _T_x */
415 PredicateValueName
= TrAmlGetNextTempName (StartNode
, &Gbl_TempCount
);
416 if (!PredicateValueName
)
421 /* First child is the Switch() predicate */
423 Next
= StartNode
->Asl
.Child
;
426 * Examine the return type of the Switch Value -
427 * must be Integer/Buffer/String
429 Index
= (UINT16
) (Next
->Asl
.ParseOpcode
- ASL_PARSE_OPCODE_BASE
);
430 Btype
= AslKeywordMapping
[Index
].AcpiBtype
;
431 if ((Btype
!= ACPI_BTYPE_INTEGER
) &&
432 (Btype
!= ACPI_BTYPE_STRING
) &&
433 (Btype
!= ACPI_BTYPE_BUFFER
))
435 AslError (ASL_WARNING
, ASL_MSG_SWITCH_TYPE
, Next
, NULL
);
436 Btype
= ACPI_BTYPE_INTEGER
;
439 /* CASE statements start at next child */
441 Peer
= Next
->Asl
.Next
;
445 Peer
= Next
->Asl
.Next
;
447 if (Next
->Asl
.ParseOpcode
== PARSEOP_CASE
)
451 /* Add an ELSE to complete the previous CASE */
457 NewOp
= TrCreateLeafNode (PARSEOP_ELSE
);
458 NewOp
->Asl
.Parent
= Conditional
->Asl
.Parent
;
459 TrAmlInitLineNumbers (NewOp
, NewOp
->Asl
.Parent
);
461 /* Link ELSE node as a peer to the previous IF */
463 TrAmlInsertPeer (Conditional
, NewOp
);
464 CurrentParentNode
= NewOp
;
468 Conditional
= CaseOp
;
469 CaseBlock
= CaseOp
->Asl
.Child
->Asl
.Next
;
470 Conditional
->Asl
.Child
->Asl
.Next
= NULL
;
471 Predicate
= CaseOp
->Asl
.Child
;
473 if ((Predicate
->Asl
.ParseOpcode
== PARSEOP_PACKAGE
) ||
474 (Predicate
->Asl
.ParseOpcode
== PARSEOP_VAR_PACKAGE
))
477 * Convert the package declaration to this form:
479 * If (LNotEqual (Match (Package(<size>){<data>},
480 * MEQ, _T_x, MTR, Zero, Zero), Ones))
482 NewOp2
= TrCreateLeafNode (PARSEOP_MATCHTYPE_MEQ
);
483 Predicate
->Asl
.Next
= NewOp2
;
484 TrAmlInitLineNumbers (NewOp2
, Conditional
);
487 NewOp2
= TrCreateValuedLeafNode (PARSEOP_NAMESTRING
,
488 (UINT64
) ACPI_TO_INTEGER (PredicateValueName
));
489 NewOp
->Asl
.Next
= NewOp2
;
490 TrAmlInitLineNumbers (NewOp2
, Predicate
);
493 NewOp2
= TrCreateLeafNode (PARSEOP_MATCHTYPE_MTR
);
494 NewOp
->Asl
.Next
= NewOp2
;
495 TrAmlInitLineNumbers (NewOp2
, Predicate
);
498 NewOp2
= TrCreateLeafNode (PARSEOP_ZERO
);
499 NewOp
->Asl
.Next
= NewOp2
;
500 TrAmlInitLineNumbers (NewOp2
, Predicate
);
503 NewOp2
= TrCreateLeafNode (PARSEOP_ZERO
);
504 NewOp
->Asl
.Next
= NewOp2
;
505 TrAmlInitLineNumbers (NewOp2
, Predicate
);
507 NewOp2
= TrCreateLeafNode (PARSEOP_MATCH
);
508 NewOp2
->Asl
.Child
= Predicate
; /* PARSEOP_PACKAGE */
509 TrAmlInitLineNumbers (NewOp2
, Conditional
);
510 TrAmlSetSubtreeParent (Predicate
, NewOp2
);
513 NewOp2
= TrCreateLeafNode (PARSEOP_ONES
);
514 NewOp
->Asl
.Next
= NewOp2
;
515 TrAmlInitLineNumbers (NewOp2
, Conditional
);
517 NewOp2
= TrCreateLeafNode (PARSEOP_LEQUAL
);
518 NewOp2
->Asl
.Child
= NewOp
;
519 NewOp
->Asl
.Parent
= NewOp2
;
520 TrAmlInitLineNumbers (NewOp2
, Conditional
);
521 TrAmlSetSubtreeParent (NewOp
, NewOp2
);
524 NewOp2
= TrCreateLeafNode (PARSEOP_LNOT
);
525 NewOp2
->Asl
.Child
= NewOp
;
526 NewOp2
->Asl
.Parent
= Conditional
;
527 NewOp
->Asl
.Parent
= NewOp2
;
528 TrAmlInitLineNumbers (NewOp2
, Conditional
);
530 Conditional
->Asl
.Child
= NewOp2
;
531 NewOp2
->Asl
.Next
= CaseBlock
;
536 * Integer and Buffer case.
538 * Change CaseOp() to: If (LEqual (SwitchValue, CaseValue)) {...}
539 * Note: SwitchValue is first to allow the CaseValue to be implicitly
540 * converted to the type of SwitchValue if necessary.
542 * CaseOp->Child is the case value
543 * CaseOp->Child->Peer is the beginning of the case block
545 NewOp
= TrCreateValuedLeafNode (PARSEOP_NAMESTRING
,
546 (UINT64
) ACPI_TO_INTEGER (PredicateValueName
));
547 NewOp
->Asl
.Next
= Predicate
;
548 TrAmlInitLineNumbers (NewOp
, Predicate
);
550 NewOp2
= TrCreateLeafNode (PARSEOP_LEQUAL
);
551 NewOp2
->Asl
.Parent
= Conditional
;
552 NewOp2
->Asl
.Child
= NewOp
;
553 TrAmlInitLineNumbers (NewOp2
, Conditional
);
555 TrAmlSetSubtreeParent (NewOp
, NewOp2
);
558 Predicate
->Asl
.Next
= CaseBlock
;
560 TrAmlSetSubtreeParent (Predicate
, Conditional
);
561 Conditional
->Asl
.Child
= Predicate
;
564 /* Reinitialize the CASE node to an IF node */
566 TrAmlInitNode (Conditional
, PARSEOP_IF
);
569 * The first CASE(IF) is not nested under an ELSE.
570 * All other CASEs are children of a parent ELSE.
572 if (CurrentParentNode
== StartNode
)
574 Conditional
->Asl
.Next
= NULL
;
579 * The IF is a child of previous IF/ELSE. It
580 * is therefore without peer.
582 CurrentParentNode
->Asl
.Child
= Conditional
;
583 Conditional
->Asl
.Parent
= CurrentParentNode
;
584 Conditional
->Asl
.Next
= NULL
;
587 else if (Next
->Asl
.ParseOpcode
== PARSEOP_DEFAULT
)
592 * More than one Default
593 * (Parser does not catch this, must check here)
595 AslError (ASL_ERROR
, ASL_MSG_MULTIPLE_DEFAULT
, Next
, NULL
);
599 /* Save the DEFAULT node for later, after CASEs */
606 /* Unknown peer opcode */
608 AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n",
609 Next
->Asl
.ParseOpName
, Next
->Asl
.ParseOpcode
);
613 /* Add the default case at the end of the if/else construct */
617 /* If no CASE statements, this is an error - see below */
621 /* Convert the DEFAULT node to an ELSE */
628 TrAmlInitNode (DefaultOp
, PARSEOP_ELSE
);
629 DefaultOp
->Asl
.Parent
= Conditional
->Asl
.Parent
;
631 /* Link ELSE node as a peer to the previous IF */
633 TrAmlInsertPeer (Conditional
, DefaultOp
);
639 AslError (ASL_ERROR
, ASL_MSG_NO_CASES
, StartNode
, NULL
);
644 * Create a Name(_T_x, ...) statement. This statement must appear at the
645 * method level, in case a loop surrounds the switch statement and could
646 * cause the name to be created twice (error).
649 /* Create the Name node */
651 Predicate
= StartNode
->Asl
.Child
;
652 NewOp
= TrCreateLeafNode (PARSEOP_NAME
);
653 TrAmlInitLineNumbers (NewOp
, StartNode
);
655 /* Find the parent method */
658 while ((Next
->Asl
.ParseOpcode
!= PARSEOP_METHOD
) &&
659 (Next
->Asl
.ParseOpcode
!= PARSEOP_DEFINITIONBLOCK
))
661 Next
= Next
->Asl
.Parent
;
665 NewOp
->Asl
.CompileFlags
|= NODE_COMPILER_EMITTED
;
666 NewOp
->Asl
.Parent
= Next
;
668 /* Insert name after the method name and arguments */
670 Next
= Next
->Asl
.Child
; /* Name */
671 Next
= Next
->Asl
.Next
; /* NumArgs */
672 Next
= Next
->Asl
.Next
; /* SerializeRule */
675 * If method is not Serialized, we must make is so, because of the way
676 * that Switch() must be implemented -- we cannot allow multiple threads
677 * to execute this method concurrently since we need to create local
680 if (Next
->Asl
.ParseOpcode
!= PARSEOP_SERIALIZERULE_SERIAL
)
682 AslError (ASL_REMARK
, ASL_MSG_SERIALIZED
, MethodOp
, "Due to use of Switch operator");
683 Next
->Asl
.ParseOpcode
= PARSEOP_SERIALIZERULE_SERIAL
;
686 Next
= Next
->Asl
.Next
; /* SyncLevel */
687 Next
= Next
->Asl
.Next
; /* ReturnType */
688 Next
= Next
->Asl
.Next
; /* ParameterTypes */
690 TrAmlInsertPeer (Next
, NewOp
);
691 TrAmlInitLineNumbers (NewOp
, Next
);
693 /* Create the NameSeg child for the Name node */
695 NewOp2
= TrCreateValuedLeafNode (PARSEOP_NAMESEG
,
696 (UINT64
) ACPI_TO_INTEGER (PredicateValueName
));
697 TrAmlInitLineNumbers (NewOp2
, NewOp
);
698 NewOp2
->Asl
.CompileFlags
|= NODE_IS_NAME_DECLARATION
;
699 NewOp
->Asl
.Child
= NewOp2
;
701 /* Create the initial value for the Name. Btype was already validated above */
705 case ACPI_BTYPE_INTEGER
:
707 NewOp2
->Asl
.Next
= TrCreateValuedLeafNode (PARSEOP_ZERO
,
709 TrAmlInitLineNumbers (NewOp2
->Asl
.Next
, NewOp
);
712 case ACPI_BTYPE_STRING
:
714 NewOp2
->Asl
.Next
= TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL
,
715 (UINT64
) ACPI_TO_INTEGER (""));
716 TrAmlInitLineNumbers (NewOp2
->Asl
.Next
, NewOp
);
719 case ACPI_BTYPE_BUFFER
:
721 (void) TrLinkPeerNode (NewOp2
, TrCreateValuedLeafNode (PARSEOP_BUFFER
,
723 Next
= NewOp2
->Asl
.Next
;
724 TrAmlInitLineNumbers (Next
, NewOp2
);
725 (void) TrLinkChildren (Next
, 1, TrCreateValuedLeafNode (PARSEOP_ZERO
,
727 TrAmlInitLineNumbers (Next
->Asl
.Child
, Next
);
729 BufferOp
= TrCreateValuedLeafNode (PARSEOP_DEFAULT_ARG
, (UINT64
) 0);
730 TrAmlInitLineNumbers (BufferOp
, Next
->Asl
.Child
);
731 (void) TrLinkPeerNode (Next
->Asl
.Child
, BufferOp
);
733 TrAmlSetSubtreeParent (Next
->Asl
.Child
, Next
);
741 TrAmlSetSubtreeParent (NewOp2
, NewOp
);
744 * Transform the Switch() into a While(One)-Break node.
745 * And create a Store() node which will be used to save the
746 * Switch() value. The store is of the form: Store (Value, _T_x)
747 * where _T_x is the temp variable.
749 TrAmlInitNode (StartNode
, PARSEOP_WHILE
);
750 NewOp
= TrCreateLeafNode (PARSEOP_ONE
);
751 TrAmlInitLineNumbers (NewOp
, StartNode
);
752 NewOp
->Asl
.Next
= Predicate
->Asl
.Next
;
753 NewOp
->Asl
.Parent
= StartNode
;
754 StartNode
->Asl
.Child
= NewOp
;
756 /* Create a Store() node */
758 StoreOp
= TrCreateLeafNode (PARSEOP_STORE
);
759 TrAmlInitLineNumbers (StoreOp
, NewOp
);
760 StoreOp
->Asl
.Parent
= StartNode
;
761 TrAmlInsertPeer (NewOp
, StoreOp
);
763 /* Complete the Store subtree */
765 StoreOp
->Asl
.Child
= Predicate
;
766 Predicate
->Asl
.Parent
= StoreOp
;
768 NewOp
= TrCreateValuedLeafNode (PARSEOP_NAMESEG
,
769 (UINT64
) ACPI_TO_INTEGER (PredicateValueName
));
770 TrAmlInitLineNumbers (NewOp
, StoreOp
);
771 NewOp
->Asl
.Parent
= StoreOp
;
772 Predicate
->Asl
.Next
= NewOp
;
774 /* Create a Break() node and insert it into the end of While() */
776 Conditional
= StartNode
->Asl
.Child
;
777 while (Conditional
->Asl
.Next
)
779 Conditional
= Conditional
->Asl
.Next
;
782 BreakOp
= TrCreateLeafNode (PARSEOP_BREAK
);
783 TrAmlInitLineNumbers (BreakOp
, NewOp
);
784 BreakOp
->Asl
.Parent
= StartNode
;
785 TrAmlInsertPeer (Conditional
, BreakOp
);