asltransform.c revision 228110
1118611Snjl 2118611Snjl/****************************************************************************** 3118611Snjl * 4118611Snjl * Module Name: asltransform - Parse tree transforms 5118611Snjl * 6118611Snjl *****************************************************************************/ 7118611Snjl 8217365Sjkim/* 9217365Sjkim * Copyright (C) 2000 - 2011, Intel Corp. 10118611Snjl * All rights reserved. 11118611Snjl * 12217365Sjkim * Redistribution and use in source and binary forms, with or without 13217365Sjkim * modification, are permitted provided that the following conditions 14217365Sjkim * are met: 15217365Sjkim * 1. Redistributions of source code must retain the above copyright 16217365Sjkim * notice, this list of conditions, and the following disclaimer, 17217365Sjkim * without modification. 18217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 20217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 21217365Sjkim * including a substantially similar Disclaimer requirement for further 22217365Sjkim * binary redistribution. 23217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 24217365Sjkim * of any contributors may be used to endorse or promote products derived 25217365Sjkim * from this software without specific prior written permission. 26118611Snjl * 27217365Sjkim * Alternatively, this software may be distributed under the terms of the 28217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 29217365Sjkim * Software Foundation. 30118611Snjl * 31217365Sjkim * NO WARRANTY 32217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 43217365Sjkim */ 44118611Snjl 45118611Snjl 46151937Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h> 47118611Snjl#include "aslcompiler.y.h" 48118611Snjl 49118611Snjl#define _COMPONENT ACPI_COMPILER 50118611Snjl ACPI_MODULE_NAME ("asltransform") 51118611Snjl 52151937Sjkim/* Local prototypes */ 53118611Snjl 54151937Sjkimstatic void 55151937SjkimTrTransformSubtree ( 56151937Sjkim ACPI_PARSE_OBJECT *Op); 57151937Sjkim 58151937Sjkimstatic char * 59151937SjkimTrAmlGetNextTempName ( 60151937Sjkim ACPI_PARSE_OBJECT *Op, 61151937Sjkim UINT8 *TempCount); 62151937Sjkim 63151937Sjkimstatic void 64151937SjkimTrAmlInitLineNumbers ( 65151937Sjkim ACPI_PARSE_OBJECT *Op, 66151937Sjkim ACPI_PARSE_OBJECT *Neighbor); 67151937Sjkim 68151937Sjkimstatic void 69151937SjkimTrAmlInitNode ( 70151937Sjkim ACPI_PARSE_OBJECT *Op, 71151937Sjkim UINT16 ParseOpcode); 72151937Sjkim 73151937Sjkimstatic void 74151937SjkimTrAmlSetSubtreeParent ( 75151937Sjkim ACPI_PARSE_OBJECT *Op, 76151937Sjkim ACPI_PARSE_OBJECT *Parent); 77151937Sjkim 78151937Sjkimstatic void 79151937SjkimTrAmlInsertPeer ( 80151937Sjkim ACPI_PARSE_OBJECT *Op, 81151937Sjkim ACPI_PARSE_OBJECT *NewPeer); 82151937Sjkim 83151937Sjkimstatic void 84151937SjkimTrDoDefinitionBlock ( 85151937Sjkim ACPI_PARSE_OBJECT *Op); 86151937Sjkim 87151937Sjkimstatic void 88151937SjkimTrDoSwitch ( 89151937Sjkim ACPI_PARSE_OBJECT *StartNode); 90151937Sjkim 91151937Sjkim 92118611Snjl/******************************************************************************* 93118611Snjl * 94118611Snjl * FUNCTION: TrAmlGetNextTempName 95118611Snjl * 96151937Sjkim * PARAMETERS: Op - Current parse op 97151937Sjkim * TempCount - Current temporary counter. Was originally 98151937Sjkim * per-module; Currently per method, could be 99151937Sjkim * expanded to per-scope. 100118611Snjl * 101151937Sjkim * RETURN: A pointer to name (allocated here). 102118611Snjl * 103138287Smarks * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are 104151937Sjkim * reserved for use by the ASL compiler. (_T_0 through _T_Z) 105118611Snjl * 106118611Snjl ******************************************************************************/ 107118611Snjl 108151937Sjkimstatic char * 109118611SnjlTrAmlGetNextTempName ( 110151937Sjkim ACPI_PARSE_OBJECT *Op, 111151937Sjkim UINT8 *TempCount) 112118611Snjl{ 113118611Snjl char *TempName; 114118611Snjl 115118611Snjl 116151937Sjkim if (*TempCount >= (10+26)) /* 0-35 valid: 0-9 and A-Z for TempName[3] */ 117118611Snjl { 118118611Snjl /* Too many temps */ 119151937Sjkim 120151937Sjkim AslError (ASL_ERROR, ASL_MSG_TOO_MANY_TEMPS, Op, NULL); 121151937Sjkim return (NULL); 122118611Snjl } 123118611Snjl 124151937Sjkim TempName = UtLocalCalloc (5); 125138287Smarks 126151937Sjkim if (*TempCount < 10) /* 0-9 */ 127138287Smarks { 128151937Sjkim TempName[3] = (char) (*TempCount + '0'); 129138287Smarks } 130151937Sjkim else /* 10-35: A-Z */ 131138287Smarks { 132151937Sjkim TempName[3] = (char) (*TempCount + ('A' - 10)); 133138287Smarks } 134151937Sjkim (*TempCount)++; 135118611Snjl 136151937Sjkim /* First three characters are always "_T_" */ 137118611Snjl 138151937Sjkim TempName[0] = '_'; 139151937Sjkim TempName[1] = 'T'; 140151937Sjkim TempName[2] = '_'; 141118611Snjl 142151937Sjkim return (TempName); 143118611Snjl} 144118611Snjl 145118611Snjl 146118611Snjl/******************************************************************************* 147118611Snjl * 148118611Snjl * FUNCTION: TrAmlInitLineNumbers 149118611Snjl * 150151937Sjkim * PARAMETERS: Op - Op to be initialized 151118611Snjl * Neighbor - Op used for initialization values 152118611Snjl * 153118611Snjl * RETURN: None 154118611Snjl * 155118611Snjl * DESCRIPTION: Initialized the various line numbers for a parse node. 156118611Snjl * 157118611Snjl ******************************************************************************/ 158118611Snjl 159151937Sjkimstatic void 160118611SnjlTrAmlInitLineNumbers ( 161118611Snjl ACPI_PARSE_OBJECT *Op, 162118611Snjl ACPI_PARSE_OBJECT *Neighbor) 163118611Snjl{ 164118611Snjl 165118611Snjl Op->Asl.EndLine = Neighbor->Asl.EndLine; 166118611Snjl Op->Asl.EndLogicalLine = Neighbor->Asl.EndLogicalLine; 167118611Snjl Op->Asl.LineNumber = Neighbor->Asl.LineNumber; 168118611Snjl Op->Asl.LogicalByteOffset = Neighbor->Asl.LogicalByteOffset; 169118611Snjl Op->Asl.LogicalLineNumber = Neighbor->Asl.LogicalLineNumber; 170118611Snjl} 171118611Snjl 172118611Snjl 173118611Snjl/******************************************************************************* 174118611Snjl * 175118611Snjl * FUNCTION: TrAmlInitNode 176118611Snjl * 177151937Sjkim * PARAMETERS: Op - Op to be initialized 178118611Snjl * ParseOpcode - Opcode for this node 179118611Snjl * 180118611Snjl * RETURN: None 181118611Snjl * 182118611Snjl * DESCRIPTION: Initialize a node with the parse opcode and opcode name. 183118611Snjl * 184118611Snjl ******************************************************************************/ 185118611Snjl 186151937Sjkimstatic void 187118611SnjlTrAmlInitNode ( 188118611Snjl ACPI_PARSE_OBJECT *Op, 189118611Snjl UINT16 ParseOpcode) 190118611Snjl{ 191118611Snjl 192118611Snjl Op->Asl.ParseOpcode = ParseOpcode; 193118611Snjl UtSetParseOpName (Op); 194118611Snjl} 195118611Snjl 196118611Snjl 197118611Snjl/******************************************************************************* 198118611Snjl * 199118611Snjl * FUNCTION: TrAmlSetSubtreeParent 200118611Snjl * 201151937Sjkim * PARAMETERS: Op - First node in a list of peer nodes 202118611Snjl * Parent - Parent of the subtree 203118611Snjl * 204118611Snjl * RETURN: None 205118611Snjl * 206118611Snjl * DESCRIPTION: Set the parent for all peer nodes in a subtree 207118611Snjl * 208118611Snjl ******************************************************************************/ 209118611Snjl 210151937Sjkimstatic void 211118611SnjlTrAmlSetSubtreeParent ( 212118611Snjl ACPI_PARSE_OBJECT *Op, 213118611Snjl ACPI_PARSE_OBJECT *Parent) 214118611Snjl{ 215118611Snjl ACPI_PARSE_OBJECT *Next; 216118611Snjl 217118611Snjl 218118611Snjl Next = Op; 219118611Snjl while (Next) 220118611Snjl { 221118611Snjl Next->Asl.Parent = Parent; 222118611Snjl Next = Next->Asl.Next; 223118611Snjl } 224118611Snjl} 225118611Snjl 226118611Snjl 227118611Snjl/******************************************************************************* 228118611Snjl * 229118611Snjl * FUNCTION: TrAmlInsertPeer 230118611Snjl * 231151937Sjkim * PARAMETERS: Op - First node in a list of peer nodes 232118611Snjl * NewPeer - Peer node to insert 233118611Snjl * 234118611Snjl * RETURN: None 235118611Snjl * 236118611Snjl * DESCRIPTION: Insert a new peer node into a list of peers. 237118611Snjl * 238118611Snjl ******************************************************************************/ 239118611Snjl 240151937Sjkimstatic void 241118611SnjlTrAmlInsertPeer ( 242118611Snjl ACPI_PARSE_OBJECT *Op, 243118611Snjl ACPI_PARSE_OBJECT *NewPeer) 244118611Snjl{ 245118611Snjl 246118611Snjl NewPeer->Asl.Next = Op->Asl.Next; 247118611Snjl Op->Asl.Next = NewPeer; 248118611Snjl} 249118611Snjl 250118611Snjl 251118611Snjl/******************************************************************************* 252118611Snjl * 253118611Snjl * FUNCTION: TrAmlTransformWalk 254118611Snjl * 255118611Snjl * PARAMETERS: ASL_WALK_CALLBACK 256118611Snjl * 257118611Snjl * RETURN: None 258118611Snjl * 259118611Snjl * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 260118611Snjl * operands. 261118611Snjl * 262118611Snjl ******************************************************************************/ 263118611Snjl 264118611SnjlACPI_STATUS 265118611SnjlTrAmlTransformWalk ( 266118611Snjl ACPI_PARSE_OBJECT *Op, 267118611Snjl UINT32 Level, 268118611Snjl void *Context) 269118611Snjl{ 270118611Snjl 271118611Snjl TrTransformSubtree (Op); 272118611Snjl return (AE_OK); 273118611Snjl} 274118611Snjl 275118611Snjl 276118611Snjl/******************************************************************************* 277118611Snjl * 278118611Snjl * FUNCTION: TrTransformSubtree 279118611Snjl * 280118611Snjl * PARAMETERS: Op - The parent parse node 281118611Snjl * 282118611Snjl * RETURN: None 283118611Snjl * 284118611Snjl * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more 285118611Snjl * complex AML opcodes require processing of the child nodes 286118611Snjl * (arguments/operands). 287118611Snjl * 288118611Snjl ******************************************************************************/ 289118611Snjl 290151937Sjkimstatic void 291118611SnjlTrTransformSubtree ( 292118611Snjl ACPI_PARSE_OBJECT *Op) 293118611Snjl{ 294118611Snjl 295118611Snjl if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) 296118611Snjl { 297118611Snjl return; 298118611Snjl } 299118611Snjl 300118611Snjl switch (Op->Asl.ParseOpcode) 301118611Snjl { 302118611Snjl case PARSEOP_DEFINITIONBLOCK: 303118611Snjl TrDoDefinitionBlock (Op); 304118611Snjl break; 305118611Snjl 306118611Snjl case PARSEOP_SWITCH: 307118611Snjl TrDoSwitch (Op); 308118611Snjl break; 309118611Snjl 310151937Sjkim case PARSEOP_METHOD: 311151937Sjkim 312151937Sjkim /* 313151937Sjkim * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global, 314151937Sjkim * however 315151937Sjkim */ 316151937Sjkim Gbl_TempCount = 0; 317151937Sjkim break; 318151937Sjkim 319118611Snjl default: 320118611Snjl /* Nothing to do here for other opcodes */ 321118611Snjl break; 322118611Snjl } 323118611Snjl} 324118611Snjl 325118611Snjl 326118611Snjl/******************************************************************************* 327118611Snjl * 328118611Snjl * FUNCTION: TrDoDefinitionBlock 329118611Snjl * 330118611Snjl * PARAMETERS: Op - Parse node 331118611Snjl * 332118611Snjl * RETURN: None 333118611Snjl * 334118611Snjl * DESCRIPTION: Find the end of the definition block and set a global to this 335118611Snjl * node. It is used by the compiler to insert compiler-generated 336118611Snjl * names at the root level of the namespace. 337118611Snjl * 338118611Snjl ******************************************************************************/ 339118611Snjl 340151937Sjkimstatic void 341118611SnjlTrDoDefinitionBlock ( 342118611Snjl ACPI_PARSE_OBJECT *Op) 343118611Snjl{ 344118611Snjl ACPI_PARSE_OBJECT *Next; 345118611Snjl UINT32 i; 346118611Snjl 347118611Snjl 348118611Snjl Next = Op->Asl.Child; 349118611Snjl for (i = 0; i < 5; i++) 350118611Snjl { 351118611Snjl Next = Next->Asl.Next; 352151937Sjkim if (i == 0) 353151937Sjkim { 354151937Sjkim /* 355151937Sjkim * This is the table signature. Only the DSDT can be assumed 356151937Sjkim * to be at the root of the namespace; Therefore, namepath 357151937Sjkim * optimization can only be performed on the DSDT. 358151937Sjkim */ 359167802Sjkim if (!ACPI_COMPARE_NAME (Next->Asl.Value.String, ACPI_SIG_DSDT)) 360151937Sjkim { 361151937Sjkim Gbl_ReferenceOptimizationFlag = FALSE; 362151937Sjkim } 363151937Sjkim } 364118611Snjl } 365118611Snjl 366118611Snjl Gbl_FirstLevelInsertionNode = Next; 367118611Snjl} 368118611Snjl 369118611Snjl 370118611Snjl/******************************************************************************* 371118611Snjl * 372118611Snjl * FUNCTION: TrDoSwitch 373118611Snjl * 374118611Snjl * PARAMETERS: StartNode - Parse node for SWITCH 375118611Snjl * 376118611Snjl * RETURN: None 377118611Snjl * 378118611Snjl * 379118611Snjl * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is 380118611Snjl * no actual AML opcode for SWITCH -- it must be simulated. 381118611Snjl * 382118611Snjl ******************************************************************************/ 383118611Snjl 384151937Sjkimstatic void 385118611SnjlTrDoSwitch ( 386118611Snjl ACPI_PARSE_OBJECT *StartNode) 387118611Snjl{ 388118611Snjl ACPI_PARSE_OBJECT *Next; 389118611Snjl ACPI_PARSE_OBJECT *CaseOp = NULL; 390118611Snjl ACPI_PARSE_OBJECT *CaseBlock = NULL; 391118611Snjl ACPI_PARSE_OBJECT *DefaultOp = NULL; 392118611Snjl ACPI_PARSE_OBJECT *CurrentParentNode; 393118611Snjl ACPI_PARSE_OBJECT *Conditional = NULL; 394118611Snjl ACPI_PARSE_OBJECT *Predicate; 395118611Snjl ACPI_PARSE_OBJECT *Peer; 396118611Snjl ACPI_PARSE_OBJECT *NewOp; 397118611Snjl ACPI_PARSE_OBJECT *NewOp2; 398193529Sjkim ACPI_PARSE_OBJECT *MethodOp; 399199337Sjkim ACPI_PARSE_OBJECT *StoreOp; 400199337Sjkim ACPI_PARSE_OBJECT *BreakOp; 401228110Sjkim ACPI_PARSE_OBJECT *BufferOp; 402118611Snjl char *PredicateValueName; 403151937Sjkim UINT16 Index; 404151937Sjkim UINT32 Btype; 405118611Snjl 406118611Snjl 407151937Sjkim /* Start node is the Switch() node */ 408151937Sjkim 409118611Snjl CurrentParentNode = StartNode; 410118611Snjl 411151937Sjkim /* Create a new temp name of the form _T_x */ 412118611Snjl 413151937Sjkim PredicateValueName = TrAmlGetNextTempName (StartNode, &Gbl_TempCount); 414151937Sjkim if (!PredicateValueName) 415151937Sjkim { 416151937Sjkim return; 417151937Sjkim } 418151937Sjkim 419151937Sjkim /* First child is the Switch() predicate */ 420151937Sjkim 421118611Snjl Next = StartNode->Asl.Child; 422118611Snjl 423151937Sjkim /* 424151937Sjkim * Examine the return type of the Switch Value - 425151937Sjkim * must be Integer/Buffer/String 426151937Sjkim */ 427151937Sjkim Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE); 428151937Sjkim Btype = AslKeywordMapping[Index].AcpiBtype; 429151937Sjkim if ((Btype != ACPI_BTYPE_INTEGER) && 430151937Sjkim (Btype != ACPI_BTYPE_STRING) && 431151937Sjkim (Btype != ACPI_BTYPE_BUFFER)) 432151937Sjkim { 433151937Sjkim AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL); 434151937Sjkim Btype = ACPI_BTYPE_INTEGER; 435151937Sjkim } 436151937Sjkim 437118611Snjl /* CASE statements start at next child */ 438118611Snjl 439151937Sjkim Peer = Next->Asl.Next; 440118611Snjl while (Peer) 441118611Snjl { 442118611Snjl Next = Peer; 443118611Snjl Peer = Next->Asl.Next; 444118611Snjl 445118611Snjl if (Next->Asl.ParseOpcode == PARSEOP_CASE) 446118611Snjl { 447118611Snjl if (CaseOp) 448118611Snjl { 449118611Snjl /* Add an ELSE to complete the previous CASE */ 450118611Snjl 451151937Sjkim if (!Conditional) 452151937Sjkim { 453151937Sjkim return; 454151937Sjkim } 455118611Snjl NewOp = TrCreateLeafNode (PARSEOP_ELSE); 456118611Snjl NewOp->Asl.Parent = Conditional->Asl.Parent; 457118611Snjl TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent); 458118611Snjl 459118611Snjl /* Link ELSE node as a peer to the previous IF */ 460118611Snjl 461118611Snjl TrAmlInsertPeer (Conditional, NewOp); 462118611Snjl CurrentParentNode = NewOp; 463118611Snjl } 464118611Snjl 465118611Snjl CaseOp = Next; 466118611Snjl Conditional = CaseOp; 467118611Snjl CaseBlock = CaseOp->Asl.Child->Asl.Next; 468118611Snjl Conditional->Asl.Child->Asl.Next = NULL; 469138287Smarks Predicate = CaseOp->Asl.Child; 470118611Snjl 471151937Sjkim if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) || 472151937Sjkim (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) 473138287Smarks { 474138287Smarks /* 475138287Smarks * Convert the package declaration to this form: 476138287Smarks * 477151937Sjkim * If (LNotEqual (Match (Package(<size>){<data>}, 478151937Sjkim * MEQ, _T_x, MTR, Zero, Zero), Ones)) 479138287Smarks */ 480138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MEQ); 481138287Smarks Predicate->Asl.Next = NewOp2; 482138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 483118611Snjl 484138287Smarks NewOp = NewOp2; 485138287Smarks NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, 486202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 487138287Smarks NewOp->Asl.Next = NewOp2; 488138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 489118611Snjl 490138287Smarks NewOp = NewOp2; 491138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MTR); 492138287Smarks NewOp->Asl.Next = NewOp2; 493138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 494118611Snjl 495138287Smarks NewOp = NewOp2; 496138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); 497138287Smarks NewOp->Asl.Next = NewOp2; 498138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 499118611Snjl 500138287Smarks NewOp = NewOp2; 501138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); 502138287Smarks NewOp->Asl.Next = NewOp2; 503138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 504118611Snjl 505138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCH); 506138287Smarks NewOp2->Asl.Child = Predicate; /* PARSEOP_PACKAGE */ 507138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 508138287Smarks TrAmlSetSubtreeParent (Predicate, NewOp2); 509138287Smarks 510138287Smarks NewOp = NewOp2; 511138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ONES); 512138287Smarks NewOp->Asl.Next = NewOp2; 513138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 514138287Smarks 515138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); 516138287Smarks NewOp2->Asl.Child = NewOp; 517138287Smarks NewOp->Asl.Parent = NewOp2; 518138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 519138287Smarks TrAmlSetSubtreeParent (NewOp, NewOp2); 520138287Smarks 521138287Smarks NewOp = NewOp2; 522138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LNOT); 523138287Smarks NewOp2->Asl.Child = NewOp; 524138287Smarks NewOp2->Asl.Parent = Conditional; 525138287Smarks NewOp->Asl.Parent = NewOp2; 526138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 527138287Smarks 528138287Smarks Conditional->Asl.Child = NewOp2; 529138287Smarks NewOp2->Asl.Next = CaseBlock; 530138287Smarks } 531138287Smarks else 532138287Smarks { 533138287Smarks /* 534151937Sjkim * Integer and Buffer case. 535151937Sjkim * 536151937Sjkim * Change CaseOp() to: If (LEqual (SwitchValue, CaseValue)) {...} 537151937Sjkim * Note: SwitchValue is first to allow the CaseValue to be implicitly 538151937Sjkim * converted to the type of SwitchValue if necessary. 539151937Sjkim * 540138287Smarks * CaseOp->Child is the case value 541138287Smarks * CaseOp->Child->Peer is the beginning of the case block 542138287Smarks */ 543138287Smarks NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, 544202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 545151937Sjkim NewOp->Asl.Next = Predicate; 546138287Smarks TrAmlInitLineNumbers (NewOp, Predicate); 547138287Smarks 548138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); 549138287Smarks NewOp2->Asl.Parent = Conditional; 550151937Sjkim NewOp2->Asl.Child = NewOp; 551138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 552138287Smarks 553151937Sjkim TrAmlSetSubtreeParent (NewOp, NewOp2); 554138287Smarks 555138287Smarks Predicate = NewOp2; 556138287Smarks Predicate->Asl.Next = CaseBlock; 557138287Smarks 558138287Smarks TrAmlSetSubtreeParent (Predicate, Conditional); 559138287Smarks Conditional->Asl.Child = Predicate; 560138287Smarks } 561138287Smarks 562118611Snjl /* Reinitialize the CASE node to an IF node */ 563118611Snjl 564118611Snjl TrAmlInitNode (Conditional, PARSEOP_IF); 565118611Snjl 566118611Snjl /* 567118611Snjl * The first CASE(IF) is not nested under an ELSE. 568118611Snjl * All other CASEs are children of a parent ELSE. 569118611Snjl */ 570118611Snjl if (CurrentParentNode == StartNode) 571118611Snjl { 572199337Sjkim Conditional->Asl.Next = NULL; 573118611Snjl } 574118611Snjl else 575118611Snjl { 576118611Snjl /* 577118611Snjl * The IF is a child of previous IF/ELSE. It 578118611Snjl * is therefore without peer. 579118611Snjl */ 580118611Snjl CurrentParentNode->Asl.Child = Conditional; 581118611Snjl Conditional->Asl.Parent = CurrentParentNode; 582118611Snjl Conditional->Asl.Next = NULL; 583118611Snjl } 584118611Snjl } 585118611Snjl else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT) 586118611Snjl { 587118611Snjl if (DefaultOp) 588118611Snjl { 589138287Smarks /* 590138287Smarks * More than one Default 591167802Sjkim * (Parser does not catch this, must check here) 592138287Smarks */ 593167802Sjkim AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL); 594118611Snjl } 595167802Sjkim else 596167802Sjkim { 597167802Sjkim /* Save the DEFAULT node for later, after CASEs */ 598118611Snjl 599167802Sjkim DefaultOp = Next; 600167802Sjkim } 601118611Snjl } 602118611Snjl else 603118611Snjl { 604138287Smarks /* Unknown peer opcode */ 605118611Snjl 606209746Sjkim AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n", 607118611Snjl Next->Asl.ParseOpName, Next->Asl.ParseOpcode); 608118611Snjl } 609118611Snjl } 610118611Snjl 611151937Sjkim /* Add the default case at the end of the if/else construct */ 612151937Sjkim 613118611Snjl if (DefaultOp) 614118611Snjl { 615138287Smarks /* If no CASE statements, this is an error - see below */ 616138287Smarks 617118611Snjl if (CaseOp) 618118611Snjl { 619138287Smarks /* Convert the DEFAULT node to an ELSE */ 620118611Snjl 621151937Sjkim if (!Conditional) 622151937Sjkim { 623151937Sjkim return; 624151937Sjkim } 625199337Sjkim 626118611Snjl TrAmlInitNode (DefaultOp, PARSEOP_ELSE); 627118611Snjl DefaultOp->Asl.Parent = Conditional->Asl.Parent; 628118611Snjl 629138287Smarks /* Link ELSE node as a peer to the previous IF */ 630138287Smarks 631138287Smarks TrAmlInsertPeer (Conditional, DefaultOp); 632118611Snjl } 633118611Snjl } 634118611Snjl 635138287Smarks if (!CaseOp) 636138287Smarks { 637138287Smarks AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL); 638138287Smarks } 639138287Smarks 640167802Sjkim 641118611Snjl /* 642167802Sjkim * Create a Name(_T_x, ...) statement. This statement must appear at the 643167802Sjkim * method level, in case a loop surrounds the switch statement and could 644167802Sjkim * cause the name to be created twice (error). 645118611Snjl */ 646167802Sjkim 647167802Sjkim /* Create the Name node */ 648167802Sjkim 649151937Sjkim Predicate = StartNode->Asl.Child; 650167802Sjkim NewOp = TrCreateLeafNode (PARSEOP_NAME); 651228110Sjkim TrAmlInitLineNumbers (NewOp, StartNode); 652151937Sjkim 653167802Sjkim /* Find the parent method */ 654151937Sjkim 655167802Sjkim Next = StartNode; 656167802Sjkim while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) && 657167802Sjkim (Next->Asl.ParseOpcode != PARSEOP_DEFINITIONBLOCK)) 658167802Sjkim { 659167802Sjkim Next = Next->Asl.Parent; 660167802Sjkim } 661193529Sjkim MethodOp = Next; 662167802Sjkim 663138287Smarks NewOp->Asl.CompileFlags |= NODE_COMPILER_EMITTED; 664167802Sjkim NewOp->Asl.Parent = Next; 665118611Snjl 666167802Sjkim /* Insert name after the method name and arguments */ 667167802Sjkim 668193529Sjkim Next = Next->Asl.Child; /* Name */ 669193529Sjkim Next = Next->Asl.Next; /* NumArgs */ 670193529Sjkim Next = Next->Asl.Next; /* SerializeRule */ 671167802Sjkim 672193529Sjkim /* 673193529Sjkim * If method is not Serialized, we must make is so, because of the way 674193529Sjkim * that Switch() must be implemented -- we cannot allow multiple threads 675193529Sjkim * to execute this method concurrently since we need to create local 676193529Sjkim * temporary name(s). 677193529Sjkim */ 678193529Sjkim if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL) 679193529Sjkim { 680193529Sjkim AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp, "Due to use of Switch operator"); 681193529Sjkim Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL; 682193529Sjkim } 683193529Sjkim 684193529Sjkim Next = Next->Asl.Next; /* SyncLevel */ 685193529Sjkim Next = Next->Asl.Next; /* ReturnType */ 686193529Sjkim Next = Next->Asl.Next; /* ParameterTypes */ 687193529Sjkim 688167802Sjkim TrAmlInsertPeer (Next, NewOp); 689167802Sjkim TrAmlInitLineNumbers (NewOp, Next); 690167802Sjkim 691167802Sjkim /* Create the NameSeg child for the Name node */ 692167802Sjkim 693151937Sjkim NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESEG, 694202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 695228110Sjkim TrAmlInitLineNumbers (NewOp2, NewOp); 696151937Sjkim NewOp2->Asl.CompileFlags |= NODE_IS_NAME_DECLARATION; 697118611Snjl NewOp->Asl.Child = NewOp2; 698118611Snjl 699167802Sjkim /* Create the initial value for the Name. Btype was already validated above */ 700118611Snjl 701151937Sjkim switch (Btype) 702151937Sjkim { 703151937Sjkim case ACPI_BTYPE_INTEGER: 704167802Sjkim NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_ZERO, 705202771Sjkim (UINT64) 0); 706228110Sjkim TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 707151937Sjkim break; 708118611Snjl 709151937Sjkim case ACPI_BTYPE_STRING: 710151937Sjkim NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL, 711202771Sjkim (UINT64) ACPI_TO_INTEGER ("")); 712228110Sjkim TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 713151937Sjkim break; 714118611Snjl 715151937Sjkim case ACPI_BTYPE_BUFFER: 716151937Sjkim (void) TrLinkPeerNode (NewOp2, TrCreateValuedLeafNode (PARSEOP_BUFFER, 717202771Sjkim (UINT64) 0)); 718151937Sjkim Next = NewOp2->Asl.Next; 719228110Sjkim TrAmlInitLineNumbers (Next, NewOp2); 720151937Sjkim (void) TrLinkChildren (Next, 1, TrCreateValuedLeafNode (PARSEOP_ZERO, 721202771Sjkim (UINT64) 1)); 722228110Sjkim TrAmlInitLineNumbers (Next->Asl.Child, Next); 723151937Sjkim 724228110Sjkim BufferOp = TrCreateValuedLeafNode (PARSEOP_DEFAULT_ARG, (UINT64) 0); 725228110Sjkim TrAmlInitLineNumbers (BufferOp, Next->Asl.Child); 726228110Sjkim (void) TrLinkPeerNode (Next->Asl.Child, BufferOp); 727228110Sjkim 728151937Sjkim TrAmlSetSubtreeParent (Next->Asl.Child, Next); 729151937Sjkim break; 730151937Sjkim 731151937Sjkim default: 732151937Sjkim break; 733151937Sjkim } 734151937Sjkim 735151937Sjkim TrAmlSetSubtreeParent (NewOp2, NewOp); 736151937Sjkim 737118611Snjl /* 738199337Sjkim * Transform the Switch() into a While(One)-Break node. 739199337Sjkim * And create a Store() node which will be used to save the 740151937Sjkim * Switch() value. The store is of the form: Store (Value, _T_x) 741151937Sjkim * where _T_x is the temp variable. 742118611Snjl */ 743199337Sjkim TrAmlInitNode (StartNode, PARSEOP_WHILE); 744199337Sjkim NewOp = TrCreateLeafNode (PARSEOP_ONE); 745228110Sjkim TrAmlInitLineNumbers (NewOp, StartNode); 746199337Sjkim NewOp->Asl.Next = Predicate->Asl.Next; 747199337Sjkim NewOp->Asl.Parent = StartNode; 748199337Sjkim StartNode->Asl.Child = NewOp; 749118611Snjl 750199337Sjkim /* Create a Store() node */ 751199337Sjkim 752199337Sjkim StoreOp = TrCreateLeafNode (PARSEOP_STORE); 753228110Sjkim TrAmlInitLineNumbers (StoreOp, NewOp); 754199337Sjkim StoreOp->Asl.Parent = StartNode; 755199337Sjkim TrAmlInsertPeer (NewOp, StoreOp); 756199337Sjkim 757151937Sjkim /* Complete the Store subtree */ 758151937Sjkim 759199337Sjkim StoreOp->Asl.Child = Predicate; 760199337Sjkim Predicate->Asl.Parent = StoreOp; 761151937Sjkim 762151937Sjkim NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESEG, 763202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 764228110Sjkim TrAmlInitLineNumbers (NewOp, StoreOp); 765199337Sjkim NewOp->Asl.Parent = StoreOp; 766118611Snjl Predicate->Asl.Next = NewOp; 767199337Sjkim 768199337Sjkim /* Create a Break() node and insert it into the end of While() */ 769199337Sjkim 770199337Sjkim Conditional = StartNode->Asl.Child; 771199337Sjkim while (Conditional->Asl.Next) 772199337Sjkim { 773199337Sjkim Conditional = Conditional->Asl.Next; 774199337Sjkim } 775199337Sjkim 776199337Sjkim BreakOp = TrCreateLeafNode (PARSEOP_BREAK); 777228110Sjkim TrAmlInitLineNumbers (BreakOp, NewOp); 778199337Sjkim BreakOp->Asl.Parent = StartNode; 779199337Sjkim TrAmlInsertPeer (Conditional, BreakOp); 780118611Snjl} 781118611Snjl 782118611Snjl 783