1118611Snjl/****************************************************************************** 2118611Snjl * 3118611Snjl * Module Name: aslopt- Compiler optimizations 4118611Snjl * 5118611Snjl *****************************************************************************/ 6118611Snjl 7217365Sjkim/* 8281075Sdim * Copyright (C) 2000 - 2015, Intel Corp. 9118611Snjl * All rights reserved. 10118611Snjl * 11217365Sjkim * Redistribution and use in source and binary forms, with or without 12217365Sjkim * modification, are permitted provided that the following conditions 13217365Sjkim * are met: 14217365Sjkim * 1. Redistributions of source code must retain the above copyright 15217365Sjkim * notice, this list of conditions, and the following disclaimer, 16217365Sjkim * without modification. 17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20217365Sjkim * including a substantially similar Disclaimer requirement for further 21217365Sjkim * binary redistribution. 22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23217365Sjkim * of any contributors may be used to endorse or promote products derived 24217365Sjkim * from this software without specific prior written permission. 25118611Snjl * 26217365Sjkim * Alternatively, this software may be distributed under the terms of the 27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28217365Sjkim * Software Foundation. 29118611Snjl * 30217365Sjkim * NO WARRANTY 31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 42217365Sjkim */ 43118611Snjl 44151937Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h> 45118611Snjl#include "aslcompiler.y.h" 46118611Snjl 47193529Sjkim#include <contrib/dev/acpica/include/acparser.h> 48193529Sjkim#include <contrib/dev/acpica/include/amlcode.h> 49193529Sjkim#include <contrib/dev/acpica/include/acnamesp.h> 50118611Snjl 51118611Snjl 52118611Snjl#define _COMPONENT ACPI_COMPILER 53118611Snjl ACPI_MODULE_NAME ("aslopt") 54118611Snjl 55118611Snjl 56151937Sjkimstatic UINT32 OptTotal = 0; 57118611Snjl 58151937Sjkim/* Local prototypes */ 59118611Snjl 60151937Sjkimstatic ACPI_STATUS 61151937SjkimOptSearchToRoot ( 62151937Sjkim ACPI_PARSE_OBJECT *Op, 63151937Sjkim ACPI_WALK_STATE *WalkState, 64151937Sjkim ACPI_NAMESPACE_NODE *CurrentNode, 65151937Sjkim ACPI_NAMESPACE_NODE *TargetNode, 66151937Sjkim ACPI_BUFFER *TargetPath, 67151937Sjkim char **NewPath); 68151937Sjkim 69151937Sjkimstatic ACPI_STATUS 70151937SjkimOptBuildShortestPath ( 71151937Sjkim ACPI_PARSE_OBJECT *Op, 72151937Sjkim ACPI_WALK_STATE *WalkState, 73151937Sjkim ACPI_NAMESPACE_NODE *CurrentNode, 74151937Sjkim ACPI_NAMESPACE_NODE *TargetNode, 75151937Sjkim ACPI_BUFFER *CurrentPath, 76151937Sjkim ACPI_BUFFER *TargetPath, 77151937Sjkim ACPI_SIZE AmlNameStringLength, 78151937Sjkim UINT8 IsDeclaration, 79151937Sjkim char **ReturnNewPath); 80151937Sjkim 81151937Sjkimstatic ACPI_STATUS 82151937SjkimOptOptimizeNameDeclaration ( 83151937Sjkim ACPI_PARSE_OBJECT *Op, 84151937Sjkim ACPI_WALK_STATE *WalkState, 85151937Sjkim ACPI_NAMESPACE_NODE *CurrentNode, 86151937Sjkim ACPI_NAMESPACE_NODE *TargetNode, 87151937Sjkim char *AmlNameString, 88151937Sjkim char **NewPath); 89151937Sjkim 90151937Sjkim 91118611Snjl/******************************************************************************* 92118611Snjl * 93118611Snjl * FUNCTION: OptSearchToRoot 94118611Snjl * 95118611Snjl * PARAMETERS: Op - Current parser op 96118611Snjl * WalkState - Current state 97118611Snjl * CurrentNode - Where we are in the namespace 98118611Snjl * TargetNode - Node to which we are referring 99118611Snjl * TargetPath - External full path to the target node 100118611Snjl * NewPath - Where the optimized path is returned 101118611Snjl * 102118611Snjl * RETURN: Status 103118611Snjl * 104118611Snjl * DESCRIPTION: Attempt to optimize a reference to a single 4-character ACPI 105118611Snjl * name utilizing the search-to-root name resolution algorithm 106118611Snjl * that is used by AML interpreters. 107118611Snjl * 108118611Snjl ******************************************************************************/ 109118611Snjl 110151937Sjkimstatic ACPI_STATUS 111118611SnjlOptSearchToRoot ( 112118611Snjl ACPI_PARSE_OBJECT *Op, 113118611Snjl ACPI_WALK_STATE *WalkState, 114118611Snjl ACPI_NAMESPACE_NODE *CurrentNode, 115118611Snjl ACPI_NAMESPACE_NODE *TargetNode, 116118611Snjl ACPI_BUFFER *TargetPath, 117118611Snjl char **NewPath) 118118611Snjl{ 119118611Snjl ACPI_NAMESPACE_NODE *Node; 120118611Snjl ACPI_GENERIC_STATE ScopeInfo; 121118611Snjl ACPI_STATUS Status; 122118611Snjl char *Path; 123118611Snjl 124118611Snjl 125167802Sjkim ACPI_FUNCTION_NAME (OptSearchToRoot); 126118611Snjl 127118611Snjl 128118611Snjl /* 129241973Sjkim * Check if search-to-root can be utilized. Use the last NameSeg of 130118611Snjl * the NamePath and 1) See if can be found and 2) If found, make 131241973Sjkim * sure that it is the same node that we want. If there is another 132118611Snjl * name in the search path before the one we want, the nodes will 133118611Snjl * not match, and we cannot use this optimization. 134118611Snjl */ 135151937Sjkim Path = &(((char *) TargetPath->Pointer)[TargetPath->Length - 136151937Sjkim ACPI_NAME_SIZE]), 137118611Snjl ScopeInfo.Scope.Node = CurrentNode; 138118611Snjl 139118611Snjl /* Lookup the NameSeg using SEARCH_PARENT (search-to-root) */ 140118611Snjl 141118611Snjl Status = AcpiNsLookup (&ScopeInfo, Path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, 142118611Snjl ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, 143118611Snjl WalkState, &(Node)); 144118611Snjl if (ACPI_FAILURE (Status)) 145118611Snjl { 146118611Snjl return (Status); 147118611Snjl } 148118611Snjl 149118611Snjl /* 150118611Snjl * We found the name, but we must check to make sure that the node 151241973Sjkim * matches. Otherwise, there is another identical name in the search 152118611Snjl * path that precludes the use of this optimization. 153118611Snjl */ 154118611Snjl if (Node != TargetNode) 155118611Snjl { 156118611Snjl /* 157118611Snjl * This means that another object with the same name was found first, 158118611Snjl * and we cannot use this optimization. 159118611Snjl */ 160118611Snjl return (AE_NOT_FOUND); 161118611Snjl } 162118611Snjl 163118611Snjl /* Found the node, we can use this optimization */ 164118611Snjl 165118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 166118611Snjl "NAMESEG: %-24s", Path)); 167118611Snjl 168118611Snjl /* We must allocate a new string for the name (TargetPath gets deleted) */ 169118611Snjl 170281075Sdim *NewPath = UtStringCacheCalloc (ACPI_NAME_SIZE + 1); 171118611Snjl ACPI_STRCPY (*NewPath, Path); 172118611Snjl 173138287Smarks if (ACPI_STRNCMP (*NewPath, "_T_", 3)) 174138287Smarks { 175138287Smarks AslError (ASL_OPTIMIZATION, ASL_MSG_SINGLE_NAME_OPTIMIZATION, Op, 176138287Smarks *NewPath); 177138287Smarks } 178118611Snjl 179118611Snjl return (AE_OK); 180118611Snjl} 181118611Snjl 182118611Snjl 183118611Snjl/******************************************************************************* 184118611Snjl * 185118611Snjl * FUNCTION: OptBuildShortestPath 186118611Snjl * 187118611Snjl * PARAMETERS: Op - Current parser op 188118611Snjl * WalkState - Current state 189118611Snjl * CurrentNode - Where we are in the namespace 190118611Snjl * TargetNode - Node to which we are referring 191118611Snjl * CurrentPath - External full path to the current node 192118611Snjl * TargetPath - External full path to the target node 193118611Snjl * AmlNameStringLength - Length of the original namepath 194118611Snjl * IsDeclaration - TRUE for declaration, FALSE for reference 195118611Snjl * ReturnNewPath - Where the optimized path is returned 196118611Snjl * 197118611Snjl * RETURN: Status 198118611Snjl * 199118611Snjl * DESCRIPTION: Build an optimal NamePath using carats 200118611Snjl * 201118611Snjl ******************************************************************************/ 202118611Snjl 203151937Sjkimstatic ACPI_STATUS 204118611SnjlOptBuildShortestPath ( 205118611Snjl ACPI_PARSE_OBJECT *Op, 206118611Snjl ACPI_WALK_STATE *WalkState, 207118611Snjl ACPI_NAMESPACE_NODE *CurrentNode, 208118611Snjl ACPI_NAMESPACE_NODE *TargetNode, 209118611Snjl ACPI_BUFFER *CurrentPath, 210118611Snjl ACPI_BUFFER *TargetPath, 211118611Snjl ACPI_SIZE AmlNameStringLength, 212118611Snjl UINT8 IsDeclaration, 213118611Snjl char **ReturnNewPath) 214118611Snjl{ 215118611Snjl UINT32 NumCommonSegments; 216118611Snjl UINT32 MaxCommonSegments; 217193529Sjkim UINT32 Index; 218118611Snjl UINT32 NumCarats; 219193529Sjkim UINT32 i; 220118611Snjl char *NewPath; 221118611Snjl char *NewPathExternal; 222118611Snjl ACPI_NAMESPACE_NODE *Node; 223118611Snjl ACPI_GENERIC_STATE ScopeInfo; 224118611Snjl ACPI_STATUS Status; 225118611Snjl BOOLEAN SubPath = FALSE; 226118611Snjl 227118611Snjl 228167802Sjkim ACPI_FUNCTION_NAME (OptBuildShortestPath); 229118611Snjl 230118611Snjl 231118611Snjl ScopeInfo.Scope.Node = CurrentNode; 232118611Snjl 233118611Snjl /* 234118611Snjl * Determine the maximum number of NameSegs that the Target and Current paths 235241973Sjkim * can possibly have in common. (To optimize, we have to have at least 1) 236118611Snjl * 237118611Snjl * Note: The external NamePath string lengths are always a multiple of 5 238118611Snjl * (ACPI_NAME_SIZE + separator) 239118611Snjl */ 240118611Snjl MaxCommonSegments = TargetPath->Length / ACPI_PATH_SEGMENT_LENGTH; 241118611Snjl if (CurrentPath->Length < TargetPath->Length) 242118611Snjl { 243118611Snjl MaxCommonSegments = CurrentPath->Length / ACPI_PATH_SEGMENT_LENGTH; 244118611Snjl } 245118611Snjl 246118611Snjl /* 247118611Snjl * Determine how many NameSegs the two paths have in common. 248118611Snjl * (Starting from the root) 249118611Snjl */ 250118611Snjl for (NumCommonSegments = 0; 251118611Snjl NumCommonSegments < MaxCommonSegments; 252118611Snjl NumCommonSegments++) 253118611Snjl { 254118611Snjl /* Compare two single NameSegs */ 255118611Snjl 256241973Sjkim if (!ACPI_COMPARE_NAME ( 257241973Sjkim &((char *) TargetPath->Pointer)[ 258241973Sjkim (NumCommonSegments * ACPI_PATH_SEGMENT_LENGTH) + 1], 259241973Sjkim &((char *) CurrentPath->Pointer)[ 260241973Sjkim (NumCommonSegments * ACPI_PATH_SEGMENT_LENGTH) + 1])) 261118611Snjl { 262118611Snjl /* Mismatch */ 263118611Snjl 264118611Snjl break; 265118611Snjl } 266118611Snjl } 267118611Snjl 268209746Sjkim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " COMMON: %u", 269151937Sjkim NumCommonSegments)); 270118611Snjl 271118611Snjl /* There must be at least 1 common NameSeg in order to optimize */ 272118611Snjl 273118611Snjl if (NumCommonSegments == 0) 274118611Snjl { 275118611Snjl return (AE_NOT_FOUND); 276118611Snjl } 277118611Snjl 278118611Snjl if (NumCommonSegments == MaxCommonSegments) 279118611Snjl { 280118611Snjl if (CurrentPath->Length == TargetPath->Length) 281118611Snjl { 282118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " SAME PATH")); 283118611Snjl return (AE_NOT_FOUND); 284118611Snjl } 285118611Snjl else 286118611Snjl { 287118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " SUBPATH")); 288118611Snjl SubPath = TRUE; 289118611Snjl } 290118611Snjl } 291118611Snjl 292118611Snjl /* Determine how many prefix Carats are required */ 293118611Snjl 294151937Sjkim NumCarats = (CurrentPath->Length / ACPI_PATH_SEGMENT_LENGTH) - 295151937Sjkim NumCommonSegments; 296118611Snjl 297118611Snjl /* 298118611Snjl * Construct a new target string 299118611Snjl */ 300167802Sjkim NewPathExternal = ACPI_ALLOCATE_ZEROED ( 301167802Sjkim TargetPath->Length + NumCarats + 1); 302118611Snjl 303118611Snjl /* Insert the Carats into the Target string */ 304118611Snjl 305118611Snjl for (i = 0; i < NumCarats; i++) 306118611Snjl { 307245582Sjkim NewPathExternal[i] = AML_PARENT_PREFIX; 308118611Snjl } 309118611Snjl 310151937Sjkim /* 311151937Sjkim * Copy only the necessary (optimal) segments from the original 312151937Sjkim * target string 313151937Sjkim */ 314118611Snjl Index = (NumCommonSegments * ACPI_PATH_SEGMENT_LENGTH) + 1; 315118611Snjl 316118611Snjl /* Special handling for exact subpath in a name declaration */ 317118611Snjl 318118611Snjl if (IsDeclaration && SubPath && (CurrentPath->Length > TargetPath->Length)) 319118611Snjl { 320118611Snjl /* 321151937Sjkim * The current path is longer than the target, and the target is a 322151937Sjkim * subpath of the current path. We must include one more NameSeg of 323151937Sjkim * the target path 324118611Snjl */ 325118611Snjl Index -= ACPI_PATH_SEGMENT_LENGTH; 326138287Smarks 327138287Smarks /* Special handling for Scope() operator */ 328138287Smarks 329138287Smarks if (Op->Asl.AmlOpcode == AML_SCOPE_OP) 330138287Smarks { 331245582Sjkim NewPathExternal[i] = AML_PARENT_PREFIX; 332138287Smarks i++; 333138287Smarks ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "(EXTRA ^)")); 334138287Smarks } 335118611Snjl } 336118611Snjl 337151937Sjkim /* Make sure we haven't gone off the end of the target path */ 338151937Sjkim 339151937Sjkim if (Index > TargetPath->Length) 340151937Sjkim { 341151937Sjkim Index = TargetPath->Length; 342151937Sjkim } 343151937Sjkim 344118611Snjl ACPI_STRCPY (&NewPathExternal[i], &((char *) TargetPath->Pointer)[Index]); 345118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " %-24s", NewPathExternal)); 346118611Snjl 347118611Snjl /* 348151937Sjkim * Internalize the new target string and check it against the original 349151937Sjkim * string to make sure that this is in fact an optimization. If the 350151937Sjkim * original string is already optimal, there is no point in continuing. 351118611Snjl */ 352118611Snjl Status = AcpiNsInternalizeName (NewPathExternal, &NewPath); 353118611Snjl if (ACPI_FAILURE (Status)) 354118611Snjl { 355151937Sjkim AslCoreSubsystemError (Op, Status, "Internalizing new NamePath", 356151937Sjkim ASL_NO_ABORT); 357167802Sjkim ACPI_FREE (NewPathExternal); 358118611Snjl return (Status); 359118611Snjl } 360118611Snjl 361118611Snjl if (ACPI_STRLEN (NewPath) >= AmlNameStringLength) 362118611Snjl { 363151937Sjkim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 364167802Sjkim " NOT SHORTER (New %u old %u)", 365193529Sjkim (UINT32) ACPI_STRLEN (NewPath), (UINT32) AmlNameStringLength)); 366167802Sjkim ACPI_FREE (NewPathExternal); 367118611Snjl return (AE_NOT_FOUND); 368118611Snjl } 369118611Snjl 370118611Snjl /* 371118611Snjl * Check to make sure that the optimization finds the node we are 372241973Sjkim * looking for. This is simply a sanity check on the new 373118611Snjl * path that has been created. 374118611Snjl */ 375118611Snjl Status = AcpiNsLookup (&ScopeInfo, NewPath, 376118611Snjl ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, 377118611Snjl ACPI_NS_DONT_OPEN_SCOPE, WalkState, &(Node)); 378118611Snjl if (ACPI_SUCCESS (Status)) 379118611Snjl { 380118611Snjl /* Found the namepath, but make sure the node is correct */ 381118611Snjl 382118611Snjl if (Node == TargetNode) 383118611Snjl { 384118611Snjl /* The lookup matched the node, accept this optimization */ 385118611Snjl 386118611Snjl AslError (ASL_OPTIMIZATION, ASL_MSG_NAME_OPTIMIZATION, 387118611Snjl Op, NewPathExternal); 388118611Snjl *ReturnNewPath = NewPath; 389118611Snjl } 390118611Snjl else 391118611Snjl { 392118611Snjl /* Node is not correct, do not use this optimization */ 393118611Snjl 394118611Snjl Status = AE_NOT_FOUND; 395118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " ***** WRONG NODE")); 396118611Snjl AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, 397118611Snjl "Not using optimized name - found wrong node"); 398118611Snjl } 399118611Snjl } 400118611Snjl else 401118611Snjl { 402118611Snjl /* The lookup failed, we obviously cannot use this optimization */ 403118611Snjl 404118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " ***** NOT FOUND")); 405118611Snjl AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, 406118611Snjl "Not using optimized name - did not find node"); 407118611Snjl } 408118611Snjl 409167802Sjkim ACPI_FREE (NewPathExternal); 410118611Snjl return (Status); 411118611Snjl} 412118611Snjl 413118611Snjl 414118611Snjl/******************************************************************************* 415118611Snjl * 416118611Snjl * FUNCTION: OptOptimizeNameDeclaration 417118611Snjl * 418118611Snjl * PARAMETERS: Op - Current parser op 419118611Snjl * WalkState - Current state 420118611Snjl * CurrentNode - Where we are in the namespace 421118611Snjl * AmlNameString - Unoptimized namepath 422118611Snjl * NewPath - Where the optimized path is returned 423118611Snjl * 424118611Snjl * RETURN: Status. AE_OK If path is optimized 425118611Snjl * 426118611Snjl * DESCRIPTION: Perform a simple optimization of removing an extraneous 427118611Snjl * backslash prefix if we are already at the root scope. 428118611Snjl * 429118611Snjl ******************************************************************************/ 430118611Snjl 431151937Sjkimstatic ACPI_STATUS 432118611SnjlOptOptimizeNameDeclaration ( 433118611Snjl ACPI_PARSE_OBJECT *Op, 434118611Snjl ACPI_WALK_STATE *WalkState, 435118611Snjl ACPI_NAMESPACE_NODE *CurrentNode, 436118611Snjl ACPI_NAMESPACE_NODE *TargetNode, 437118611Snjl char *AmlNameString, 438118611Snjl char **NewPath) 439118611Snjl{ 440118611Snjl ACPI_STATUS Status; 441118611Snjl char *NewPathExternal; 442118611Snjl ACPI_NAMESPACE_NODE *Node; 443118611Snjl 444118611Snjl 445167802Sjkim ACPI_FUNCTION_TRACE (OptOptimizeNameDeclaration); 446118611Snjl 447118611Snjl 448118611Snjl if (((CurrentNode == AcpiGbl_RootNode) || 449118611Snjl (Op->Common.Parent->Asl.ParseOpcode == PARSEOP_DEFINITIONBLOCK)) && 450245582Sjkim (ACPI_IS_ROOT_PREFIX (AmlNameString[0]))) 451118611Snjl { 452118611Snjl /* 453118611Snjl * The current scope is the root, and the namepath has a root prefix 454241973Sjkim * that is therefore extraneous. Remove it. 455118611Snjl */ 456118611Snjl *NewPath = &AmlNameString[1]; 457118611Snjl 458118611Snjl /* Debug output */ 459118611Snjl 460118611Snjl Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, *NewPath, 461118611Snjl NULL, &NewPathExternal); 462118611Snjl if (ACPI_FAILURE (Status)) 463118611Snjl { 464151937Sjkim AslCoreSubsystemError (Op, Status, "Externalizing NamePath", 465151937Sjkim ASL_NO_ABORT); 466118611Snjl return (Status); 467118611Snjl } 468118611Snjl 469118611Snjl /* 470118611Snjl * Check to make sure that the optimization finds the node we are 471241973Sjkim * looking for. This is simply a sanity check on the new 472118611Snjl * path that has been created. 473240716Sjkim * 474240716Sjkim * We know that we are at the root, so NULL is used for the scope. 475118611Snjl */ 476240716Sjkim Status = AcpiNsLookup (NULL, *NewPath, 477118611Snjl ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, 478118611Snjl ACPI_NS_DONT_OPEN_SCOPE, WalkState, &(Node)); 479118611Snjl if (ACPI_SUCCESS (Status)) 480118611Snjl { 481118611Snjl /* Found the namepath, but make sure the node is correct */ 482118611Snjl 483118611Snjl if (Node == TargetNode) 484118611Snjl { 485118611Snjl /* The lookup matched the node, accept this optimization */ 486118611Snjl 487118611Snjl AslError (ASL_OPTIMIZATION, ASL_MSG_NAME_OPTIMIZATION, 488118611Snjl Op, NewPathExternal); 489118611Snjl 490118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 491118611Snjl "AT ROOT: %-24s", NewPathExternal)); 492118611Snjl } 493118611Snjl else 494118611Snjl { 495118611Snjl /* Node is not correct, do not use this optimization */ 496118611Snjl 497118611Snjl Status = AE_NOT_FOUND; 498151937Sjkim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 499151937Sjkim " ***** WRONG NODE")); 500118611Snjl AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, 501118611Snjl "Not using optimized name - found wrong node"); 502118611Snjl } 503118611Snjl } 504118611Snjl else 505118611Snjl { 506118611Snjl /* The lookup failed, we obviously cannot use this optimization */ 507118611Snjl 508151937Sjkim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 509151937Sjkim " ***** NOT FOUND")); 510118611Snjl AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, 511118611Snjl "Not using optimized name - did not find node"); 512118611Snjl } 513118611Snjl 514167802Sjkim ACPI_FREE (NewPathExternal); 515118611Snjl return (Status); 516118611Snjl } 517118611Snjl 518118611Snjl /* Could not optimize */ 519118611Snjl 520118611Snjl return (AE_NOT_FOUND); 521118611Snjl} 522118611Snjl 523118611Snjl 524118611Snjl/******************************************************************************* 525118611Snjl * 526118611Snjl * FUNCTION: OptOptimizeNamePath 527118611Snjl * 528118611Snjl * PARAMETERS: Op - Current parser op 529118611Snjl * Flags - Opcode info flags 530118611Snjl * WalkState - Current state 531118611Snjl * AmlNameString - Unoptimized namepath 532118611Snjl * TargetNode - Node to which AmlNameString refers 533118611Snjl * 534241973Sjkim * RETURN: None. If path is optimized, the Op is updated with new path 535118611Snjl * 536118611Snjl * DESCRIPTION: Optimize a Named Declaration or Reference to the minimal length. 537118611Snjl * Must take into account both the current location in the 538118611Snjl * namespace and the actual reference path. 539118611Snjl * 540118611Snjl ******************************************************************************/ 541118611Snjl 542118611Snjlvoid 543118611SnjlOptOptimizeNamePath ( 544118611Snjl ACPI_PARSE_OBJECT *Op, 545118611Snjl UINT32 Flags, 546118611Snjl ACPI_WALK_STATE *WalkState, 547118611Snjl char *AmlNameString, 548118611Snjl ACPI_NAMESPACE_NODE *TargetNode) 549118611Snjl{ 550118611Snjl ACPI_STATUS Status; 551118611Snjl ACPI_BUFFER TargetPath; 552118611Snjl ACPI_BUFFER CurrentPath; 553118611Snjl ACPI_SIZE AmlNameStringLength; 554118611Snjl ACPI_NAMESPACE_NODE *CurrentNode; 555118611Snjl char *ExternalNameString; 556118611Snjl char *NewPath = NULL; 557118611Snjl ACPI_SIZE HowMuchShorter; 558118611Snjl ACPI_PARSE_OBJECT *NextOp; 559118611Snjl 560118611Snjl 561167802Sjkim ACPI_FUNCTION_TRACE (OptOptimizeNamePath); 562118611Snjl 563118611Snjl 564118611Snjl /* This is an optional optimization */ 565118611Snjl 566118611Snjl if (!Gbl_ReferenceOptimizationFlag) 567118611Snjl { 568118611Snjl return_VOID; 569118611Snjl } 570118611Snjl 571118611Snjl /* Various required items */ 572118611Snjl 573138287Smarks if (!TargetNode || !WalkState || !AmlNameString || !Op->Common.Parent) 574118611Snjl { 575118611Snjl return_VOID; 576118611Snjl } 577118611Snjl 578281075Sdim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 579281075Sdim "PATH OPTIMIZE: Line %5d ParentOp [%12.12s] ThisOp [%12.12s] ", 580118611Snjl Op->Asl.LogicalLineNumber, 581118611Snjl AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), 582118611Snjl AcpiPsGetOpcodeName (Op->Common.AmlOpcode))); 583118611Snjl 584118611Snjl if (!(Flags & (AML_NAMED | AML_CREATE))) 585118611Snjl { 586118611Snjl if (Op->Asl.CompileFlags & NODE_IS_NAME_DECLARATION) 587118611Snjl { 588118611Snjl /* We don't want to fuss with actual name declaration nodes here */ 589118611Snjl 590118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 591118611Snjl "******* NAME DECLARATION\n")); 592118611Snjl return_VOID; 593118611Snjl } 594118611Snjl } 595118611Snjl 596118611Snjl /* 597118611Snjl * The original path must be longer than one NameSeg (4 chars) for there 598118611Snjl * to be any possibility that it can be optimized to a shorter string 599118611Snjl */ 600118611Snjl AmlNameStringLength = ACPI_STRLEN (AmlNameString); 601118611Snjl if (AmlNameStringLength <= ACPI_NAME_SIZE) 602118611Snjl { 603118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 604118611Snjl "NAMESEG %4.4s\n", AmlNameString)); 605118611Snjl return_VOID; 606118611Snjl } 607118611Snjl 608118611Snjl /* 609118611Snjl * We need to obtain the node that represents the current scope -- where 610241973Sjkim * we are right now in the namespace. We will compare this path 611118611Snjl * against the Namepath, looking for commonality. 612118611Snjl */ 613118611Snjl CurrentNode = AcpiGbl_RootNode; 614118611Snjl if (WalkState->ScopeInfo) 615118611Snjl { 616118611Snjl CurrentNode = WalkState->ScopeInfo->Scope.Node; 617118611Snjl } 618118611Snjl 619118611Snjl if (Flags & (AML_NAMED | AML_CREATE)) 620118611Snjl { 621118611Snjl /* This is the declaration of a new name */ 622118611Snjl 623281075Sdim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "NAME\n")); 624118611Snjl 625151937Sjkim /* 626240716Sjkim * The node of interest is the parent of this node (the containing 627240716Sjkim * scope). The actual namespace node may be up more than one level 628240716Sjkim * of parse op or it may not exist at all (if we traverse back 629240716Sjkim * up to the root.) 630151937Sjkim */ 631240716Sjkim NextOp = Op->Asl.Parent; 632240716Sjkim while (NextOp && (!NextOp->Asl.Node)) 633118611Snjl { 634240716Sjkim NextOp = NextOp->Asl.Parent; 635240716Sjkim } 636240716Sjkim if (NextOp && NextOp->Asl.Node) 637240716Sjkim { 638240716Sjkim CurrentNode = NextOp->Asl.Node; 639240716Sjkim } 640240716Sjkim else 641240716Sjkim { 642118611Snjl CurrentNode = AcpiGbl_RootNode; 643118611Snjl } 644118611Snjl } 645118611Snjl else 646118611Snjl { 647118611Snjl /* This is a reference to an existing named object */ 648118611Snjl 649281075Sdim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "REFERENCE\n")); 650118611Snjl } 651118611Snjl 652118611Snjl /* 653118611Snjl * Obtain the full paths to the two nodes that we are interested in 654118611Snjl * (Target and current namespace location) in external 655118611Snjl * format -- something we can easily manipulate 656118611Snjl */ 657118611Snjl TargetPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 658118611Snjl Status = AcpiNsHandleToPathname (TargetNode, &TargetPath); 659118611Snjl if (ACPI_FAILURE (Status)) 660118611Snjl { 661151937Sjkim AslCoreSubsystemError (Op, Status, "Getting Target NamePath", 662151937Sjkim ASL_NO_ABORT); 663118611Snjl return_VOID; 664118611Snjl } 665118611Snjl TargetPath.Length--; /* Subtract one for null terminator */ 666118611Snjl 667118611Snjl /* CurrentPath is the path to this scope (where we are in the namespace) */ 668118611Snjl 669118611Snjl CurrentPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 670118611Snjl Status = AcpiNsHandleToPathname (CurrentNode, &CurrentPath); 671118611Snjl if (ACPI_FAILURE (Status)) 672118611Snjl { 673151937Sjkim AslCoreSubsystemError (Op, Status, "Getting Current NamePath", 674151937Sjkim ASL_NO_ABORT); 675118611Snjl return_VOID; 676118611Snjl } 677118611Snjl CurrentPath.Length--; /* Subtract one for null terminator */ 678118611Snjl 679118611Snjl /* Debug output only */ 680118611Snjl 681118611Snjl Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, AmlNameString, 682118611Snjl NULL, &ExternalNameString); 683118611Snjl if (ACPI_FAILURE (Status)) 684118611Snjl { 685151937Sjkim AslCoreSubsystemError (Op, Status, "Externalizing NamePath", 686151937Sjkim ASL_NO_ABORT); 687118611Snjl return_VOID; 688118611Snjl } 689118611Snjl 690118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 691281075Sdim "CURRENT SCOPE: (%2u) %-37s FULL PATH TO NAME: (%2u) %-32s ACTUAL AML:%-32s\n", 692281075Sdim (UINT32) CurrentPath.Length, (char *) CurrentPath.Pointer, 693281075Sdim (UINT32) TargetPath.Length, (char *) TargetPath.Pointer, 694281075Sdim ExternalNameString)); 695118611Snjl 696167802Sjkim ACPI_FREE (ExternalNameString); 697118611Snjl 698118611Snjl /* 699118611Snjl * Attempt an optmization depending on the type of namepath 700118611Snjl */ 701118611Snjl if (Flags & (AML_NAMED | AML_CREATE)) 702118611Snjl { 703118611Snjl /* 704118611Snjl * This is a named opcode and the namepath is a name declaration, not 705118611Snjl * a reference. 706118611Snjl */ 707118611Snjl Status = OptOptimizeNameDeclaration (Op, WalkState, CurrentNode, 708118611Snjl TargetNode, AmlNameString, &NewPath); 709118611Snjl if (ACPI_FAILURE (Status)) 710118611Snjl { 711118611Snjl /* 712118611Snjl * 2) now attempt to 713118611Snjl * optimize the namestring with carats (up-arrow) 714118611Snjl */ 715118611Snjl Status = OptBuildShortestPath (Op, WalkState, CurrentNode, 716118611Snjl TargetNode, &CurrentPath, &TargetPath, 717118611Snjl AmlNameStringLength, 1, &NewPath); 718118611Snjl } 719118611Snjl } 720118611Snjl else 721118611Snjl { 722118611Snjl /* 723118611Snjl * This is a reference to an existing named object 724118611Snjl * 725118611Snjl * 1) Check if search-to-root can be utilized using the last 726118611Snjl * NameSeg of the NamePath 727118611Snjl */ 728118611Snjl Status = OptSearchToRoot (Op, WalkState, CurrentNode, 729118611Snjl TargetNode, &TargetPath, &NewPath); 730118611Snjl if (ACPI_FAILURE (Status)) 731118611Snjl { 732118611Snjl /* 733118611Snjl * 2) Search-to-root could not be used, now attempt to 734118611Snjl * optimize the namestring with carats (up-arrow) 735118611Snjl */ 736118611Snjl Status = OptBuildShortestPath (Op, WalkState, CurrentNode, 737118611Snjl TargetNode, &CurrentPath, &TargetPath, 738118611Snjl AmlNameStringLength, 0, &NewPath); 739118611Snjl } 740118611Snjl } 741118611Snjl 742118611Snjl /* 743118611Snjl * Success from above indicates that the NamePath was successfully 744241973Sjkim * optimized. We need to update the parse op with the new name 745118611Snjl */ 746118611Snjl if (ACPI_SUCCESS (Status)) 747118611Snjl { 748118611Snjl HowMuchShorter = (AmlNameStringLength - ACPI_STRLEN (NewPath)); 749118611Snjl OptTotal += HowMuchShorter; 750118611Snjl 751281075Sdim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 752281075Sdim " REDUCED BY %2u (TOTAL SAVED %2u)", 753193529Sjkim (UINT32) HowMuchShorter, OptTotal)); 754118611Snjl 755118611Snjl if (Flags & AML_NAMED) 756118611Snjl { 757118611Snjl if (Op->Asl.AmlOpcode == AML_ALIAS_OP) 758118611Snjl { 759118611Snjl /* 760118611Snjl * ALIAS is the only oddball opcode, the name declaration 761118611Snjl * (alias name) is the second operand 762118611Snjl */ 763118611Snjl Op->Asl.Child->Asl.Next->Asl.Value.String = NewPath; 764118611Snjl Op->Asl.Child->Asl.Next->Asl.AmlLength = ACPI_STRLEN (NewPath); 765118611Snjl } 766118611Snjl else 767118611Snjl { 768118611Snjl Op->Asl.Child->Asl.Value.String = NewPath; 769118611Snjl Op->Asl.Child->Asl.AmlLength = ACPI_STRLEN (NewPath); 770118611Snjl } 771118611Snjl } 772118611Snjl else if (Flags & AML_CREATE) 773118611Snjl { 774118611Snjl /* Name must appear as the last parameter */ 775118611Snjl 776118611Snjl NextOp = Op->Asl.Child; 777118611Snjl while (!(NextOp->Asl.CompileFlags & NODE_IS_NAME_DECLARATION)) 778118611Snjl { 779118611Snjl NextOp = NextOp->Asl.Next; 780118611Snjl } 781118611Snjl /* Update the parse node with the new NamePath */ 782118611Snjl 783118611Snjl NextOp->Asl.Value.String = NewPath; 784118611Snjl NextOp->Asl.AmlLength = ACPI_STRLEN (NewPath); 785118611Snjl } 786118611Snjl else 787118611Snjl { 788118611Snjl /* Update the parse node with the new NamePath */ 789118611Snjl 790118611Snjl Op->Asl.Value.String = NewPath; 791118611Snjl Op->Asl.AmlLength = ACPI_STRLEN (NewPath); 792118611Snjl } 793118611Snjl } 794118611Snjl else 795118611Snjl { 796118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " ALREADY OPTIMAL")); 797118611Snjl } 798118611Snjl 799118611Snjl /* Cleanup path buffers */ 800118611Snjl 801167802Sjkim ACPI_FREE (TargetPath.Pointer); 802167802Sjkim ACPI_FREE (CurrentPath.Pointer); 803118611Snjl 804118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "\n")); 805118611Snjl return_VOID; 806118611Snjl} 807