1118611Snjl/****************************************************************************** 2118611Snjl * 3118611Snjl * Module Name: aslopt- Compiler optimizations 4118611Snjl * 5118611Snjl *****************************************************************************/ 6118611Snjl 7217365Sjkim/* 8306536Sjkim * Copyright (C) 2000 - 2016, 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 56306536Sjkimstatic 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 */ 135306536Sjkim Path = &(((char *) TargetPath->Pointer)[ 136306536Sjkim TargetPath->Length - 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, 142306536Sjkim ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, 143306536Sjkim 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); 171306536Sjkim strcpy (*NewPath, Path); 172118611Snjl 173306536Sjkim if (strncmp (*NewPath, "_T_", 3)) 174138287Smarks { 175306536Sjkim AslError (ASL_OPTIMIZATION, ASL_MSG_SINGLE_NAME_OPTIMIZATION, 176306536Sjkim Op, *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; 220306536Sjkim char *NewPathInternal; 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 256306536Sjkim Index = (NumCommonSegments * ACPI_PATH_SEGMENT_LENGTH) + 1; 257306536Sjkim 258241973Sjkim if (!ACPI_COMPARE_NAME ( 259306536Sjkim &(ACPI_CAST_PTR (char, TargetPath->Pointer)) [Index], 260306536Sjkim &(ACPI_CAST_PTR (char, CurrentPath->Pointer)) [Index])) 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) - 295306536Sjkim NumCommonSegments; 296118611Snjl 297118611Snjl /* 298118611Snjl * Construct a new target string 299118611Snjl */ 300306536Sjkim NewPathExternal = 301306536Sjkim ACPI_ALLOCATE_ZEROED (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 318306536Sjkim if (IsDeclaration && SubPath && 319306536Sjkim (CurrentPath->Length > TargetPath->Length)) 320118611Snjl { 321118611Snjl /* 322151937Sjkim * The current path is longer than the target, and the target is a 323151937Sjkim * subpath of the current path. We must include one more NameSeg of 324151937Sjkim * the target path 325118611Snjl */ 326118611Snjl Index -= ACPI_PATH_SEGMENT_LENGTH; 327138287Smarks 328138287Smarks /* Special handling for Scope() operator */ 329138287Smarks 330138287Smarks if (Op->Asl.AmlOpcode == AML_SCOPE_OP) 331138287Smarks { 332245582Sjkim NewPathExternal[i] = AML_PARENT_PREFIX; 333138287Smarks i++; 334138287Smarks ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "(EXTRA ^)")); 335138287Smarks } 336118611Snjl } 337118611Snjl 338151937Sjkim /* Make sure we haven't gone off the end of the target path */ 339151937Sjkim 340151937Sjkim if (Index > TargetPath->Length) 341151937Sjkim { 342151937Sjkim Index = TargetPath->Length; 343151937Sjkim } 344151937Sjkim 345306536Sjkim strcpy (&NewPathExternal[i], 346306536Sjkim &(ACPI_CAST_PTR (char, TargetPath->Pointer))[Index]); 347118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " %-24s", NewPathExternal)); 348118611Snjl 349118611Snjl /* 350151937Sjkim * Internalize the new target string and check it against the original 351151937Sjkim * string to make sure that this is in fact an optimization. If the 352151937Sjkim * original string is already optimal, there is no point in continuing. 353118611Snjl */ 354306536Sjkim Status = AcpiNsInternalizeName (NewPathExternal, &NewPathInternal); 355118611Snjl if (ACPI_FAILURE (Status)) 356118611Snjl { 357151937Sjkim AslCoreSubsystemError (Op, Status, "Internalizing new NamePath", 358151937Sjkim ASL_NO_ABORT); 359306536Sjkim goto Cleanup; 360118611Snjl } 361118611Snjl 362306536Sjkim if (strlen (NewPathInternal) >= AmlNameStringLength) 363118611Snjl { 364151937Sjkim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 365167802Sjkim " NOT SHORTER (New %u old %u)", 366306536Sjkim (UINT32) strlen (NewPathInternal), 367306536Sjkim (UINT32) AmlNameStringLength)); 368306536Sjkim 369306536Sjkim ACPI_FREE (NewPathInternal); 370306536Sjkim Status = AE_NOT_FOUND; 371306536Sjkim goto Cleanup; 372118611Snjl } 373118611Snjl 374118611Snjl /* 375118611Snjl * Check to make sure that the optimization finds the node we are 376241973Sjkim * looking for. This is simply a sanity check on the new 377118611Snjl * path that has been created. 378118611Snjl */ 379306536Sjkim Status = AcpiNsLookup (&ScopeInfo, NewPathInternal, 380306536Sjkim ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, 381306536Sjkim ACPI_NS_DONT_OPEN_SCOPE, WalkState, &(Node)); 382118611Snjl if (ACPI_SUCCESS (Status)) 383118611Snjl { 384118611Snjl /* Found the namepath, but make sure the node is correct */ 385118611Snjl 386118611Snjl if (Node == TargetNode) 387118611Snjl { 388118611Snjl /* The lookup matched the node, accept this optimization */ 389118611Snjl 390118611Snjl AslError (ASL_OPTIMIZATION, ASL_MSG_NAME_OPTIMIZATION, 391118611Snjl Op, NewPathExternal); 392306536Sjkim *ReturnNewPath = NewPathInternal; 393118611Snjl } 394118611Snjl else 395118611Snjl { 396118611Snjl /* Node is not correct, do not use this optimization */ 397118611Snjl 398118611Snjl Status = AE_NOT_FOUND; 399118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " ***** WRONG NODE")); 400118611Snjl AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, 401118611Snjl "Not using optimized name - found wrong node"); 402118611Snjl } 403118611Snjl } 404118611Snjl else 405118611Snjl { 406118611Snjl /* The lookup failed, we obviously cannot use this optimization */ 407118611Snjl 408306536Sjkim ACPI_FREE (NewPathInternal); 409306536Sjkim 410118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " ***** NOT FOUND")); 411118611Snjl AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, 412118611Snjl "Not using optimized name - did not find node"); 413118611Snjl } 414118611Snjl 415306536SjkimCleanup: 416306536Sjkim 417167802Sjkim ACPI_FREE (NewPathExternal); 418118611Snjl return (Status); 419118611Snjl} 420118611Snjl 421118611Snjl 422118611Snjl/******************************************************************************* 423118611Snjl * 424118611Snjl * FUNCTION: OptOptimizeNameDeclaration 425118611Snjl * 426118611Snjl * PARAMETERS: Op - Current parser op 427118611Snjl * WalkState - Current state 428118611Snjl * CurrentNode - Where we are in the namespace 429118611Snjl * AmlNameString - Unoptimized namepath 430118611Snjl * NewPath - Where the optimized path is returned 431118611Snjl * 432118611Snjl * RETURN: Status. AE_OK If path is optimized 433118611Snjl * 434118611Snjl * DESCRIPTION: Perform a simple optimization of removing an extraneous 435118611Snjl * backslash prefix if we are already at the root scope. 436118611Snjl * 437118611Snjl ******************************************************************************/ 438118611Snjl 439151937Sjkimstatic ACPI_STATUS 440118611SnjlOptOptimizeNameDeclaration ( 441118611Snjl ACPI_PARSE_OBJECT *Op, 442118611Snjl ACPI_WALK_STATE *WalkState, 443118611Snjl ACPI_NAMESPACE_NODE *CurrentNode, 444118611Snjl ACPI_NAMESPACE_NODE *TargetNode, 445118611Snjl char *AmlNameString, 446118611Snjl char **NewPath) 447118611Snjl{ 448118611Snjl ACPI_STATUS Status; 449118611Snjl char *NewPathExternal; 450118611Snjl ACPI_NAMESPACE_NODE *Node; 451118611Snjl 452118611Snjl 453167802Sjkim ACPI_FUNCTION_TRACE (OptOptimizeNameDeclaration); 454118611Snjl 455118611Snjl 456118611Snjl if (((CurrentNode == AcpiGbl_RootNode) || 457306536Sjkim (Op->Common.Parent->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)) && 458245582Sjkim (ACPI_IS_ROOT_PREFIX (AmlNameString[0]))) 459118611Snjl { 460118611Snjl /* 461118611Snjl * The current scope is the root, and the namepath has a root prefix 462241973Sjkim * that is therefore extraneous. Remove it. 463118611Snjl */ 464118611Snjl *NewPath = &AmlNameString[1]; 465118611Snjl 466118611Snjl /* Debug output */ 467118611Snjl 468118611Snjl Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, *NewPath, 469306536Sjkim NULL, &NewPathExternal); 470118611Snjl if (ACPI_FAILURE (Status)) 471118611Snjl { 472151937Sjkim AslCoreSubsystemError (Op, Status, "Externalizing NamePath", 473151937Sjkim ASL_NO_ABORT); 474118611Snjl return (Status); 475118611Snjl } 476118611Snjl 477118611Snjl /* 478118611Snjl * Check to make sure that the optimization finds the node we are 479241973Sjkim * looking for. This is simply a sanity check on the new 480118611Snjl * path that has been created. 481240716Sjkim * 482240716Sjkim * We know that we are at the root, so NULL is used for the scope. 483118611Snjl */ 484240716Sjkim Status = AcpiNsLookup (NULL, *NewPath, 485306536Sjkim ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, 486306536Sjkim ACPI_NS_DONT_OPEN_SCOPE, WalkState, &(Node)); 487118611Snjl if (ACPI_SUCCESS (Status)) 488118611Snjl { 489118611Snjl /* Found the namepath, but make sure the node is correct */ 490118611Snjl 491118611Snjl if (Node == TargetNode) 492118611Snjl { 493118611Snjl /* The lookup matched the node, accept this optimization */ 494118611Snjl 495118611Snjl AslError (ASL_OPTIMIZATION, ASL_MSG_NAME_OPTIMIZATION, 496118611Snjl Op, NewPathExternal); 497118611Snjl 498118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 499118611Snjl "AT ROOT: %-24s", NewPathExternal)); 500118611Snjl } 501118611Snjl else 502118611Snjl { 503118611Snjl /* Node is not correct, do not use this optimization */ 504118611Snjl 505118611Snjl Status = AE_NOT_FOUND; 506151937Sjkim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 507151937Sjkim " ***** WRONG NODE")); 508118611Snjl AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, 509118611Snjl "Not using optimized name - found wrong node"); 510118611Snjl } 511118611Snjl } 512118611Snjl else 513118611Snjl { 514118611Snjl /* The lookup failed, we obviously cannot use this optimization */ 515118611Snjl 516151937Sjkim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 517151937Sjkim " ***** NOT FOUND")); 518118611Snjl AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op, 519118611Snjl "Not using optimized name - did not find node"); 520118611Snjl } 521118611Snjl 522167802Sjkim ACPI_FREE (NewPathExternal); 523118611Snjl return (Status); 524118611Snjl } 525118611Snjl 526118611Snjl /* Could not optimize */ 527118611Snjl 528118611Snjl return (AE_NOT_FOUND); 529118611Snjl} 530118611Snjl 531118611Snjl 532118611Snjl/******************************************************************************* 533118611Snjl * 534118611Snjl * FUNCTION: OptOptimizeNamePath 535118611Snjl * 536118611Snjl * PARAMETERS: Op - Current parser op 537118611Snjl * Flags - Opcode info flags 538118611Snjl * WalkState - Current state 539118611Snjl * AmlNameString - Unoptimized namepath 540118611Snjl * TargetNode - Node to which AmlNameString refers 541118611Snjl * 542241973Sjkim * RETURN: None. If path is optimized, the Op is updated with new path 543118611Snjl * 544118611Snjl * DESCRIPTION: Optimize a Named Declaration or Reference to the minimal length. 545118611Snjl * Must take into account both the current location in the 546118611Snjl * namespace and the actual reference path. 547118611Snjl * 548118611Snjl ******************************************************************************/ 549118611Snjl 550118611Snjlvoid 551118611SnjlOptOptimizeNamePath ( 552118611Snjl ACPI_PARSE_OBJECT *Op, 553118611Snjl UINT32 Flags, 554118611Snjl ACPI_WALK_STATE *WalkState, 555118611Snjl char *AmlNameString, 556118611Snjl ACPI_NAMESPACE_NODE *TargetNode) 557118611Snjl{ 558118611Snjl ACPI_STATUS Status; 559118611Snjl ACPI_BUFFER TargetPath; 560118611Snjl ACPI_BUFFER CurrentPath; 561118611Snjl ACPI_SIZE AmlNameStringLength; 562118611Snjl ACPI_NAMESPACE_NODE *CurrentNode; 563118611Snjl char *ExternalNameString; 564118611Snjl char *NewPath = NULL; 565118611Snjl ACPI_SIZE HowMuchShorter; 566118611Snjl ACPI_PARSE_OBJECT *NextOp; 567118611Snjl 568118611Snjl 569167802Sjkim ACPI_FUNCTION_TRACE (OptOptimizeNamePath); 570118611Snjl 571118611Snjl 572118611Snjl /* This is an optional optimization */ 573118611Snjl 574118611Snjl if (!Gbl_ReferenceOptimizationFlag) 575118611Snjl { 576118611Snjl return_VOID; 577118611Snjl } 578118611Snjl 579118611Snjl /* Various required items */ 580118611Snjl 581138287Smarks if (!TargetNode || !WalkState || !AmlNameString || !Op->Common.Parent) 582118611Snjl { 583118611Snjl return_VOID; 584118611Snjl } 585118611Snjl 586281075Sdim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 587281075Sdim "PATH OPTIMIZE: Line %5d ParentOp [%12.12s] ThisOp [%12.12s] ", 588118611Snjl Op->Asl.LogicalLineNumber, 589118611Snjl AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), 590118611Snjl AcpiPsGetOpcodeName (Op->Common.AmlOpcode))); 591118611Snjl 592118611Snjl if (!(Flags & (AML_NAMED | AML_CREATE))) 593118611Snjl { 594118611Snjl if (Op->Asl.CompileFlags & NODE_IS_NAME_DECLARATION) 595118611Snjl { 596118611Snjl /* We don't want to fuss with actual name declaration nodes here */ 597118611Snjl 598118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 599118611Snjl "******* NAME DECLARATION\n")); 600118611Snjl return_VOID; 601118611Snjl } 602118611Snjl } 603118611Snjl 604118611Snjl /* 605118611Snjl * The original path must be longer than one NameSeg (4 chars) for there 606118611Snjl * to be any possibility that it can be optimized to a shorter string 607118611Snjl */ 608306536Sjkim AmlNameStringLength = strlen (AmlNameString); 609118611Snjl if (AmlNameStringLength <= ACPI_NAME_SIZE) 610118611Snjl { 611118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 612118611Snjl "NAMESEG %4.4s\n", AmlNameString)); 613118611Snjl return_VOID; 614118611Snjl } 615118611Snjl 616118611Snjl /* 617118611Snjl * We need to obtain the node that represents the current scope -- where 618241973Sjkim * we are right now in the namespace. We will compare this path 619118611Snjl * against the Namepath, looking for commonality. 620118611Snjl */ 621118611Snjl CurrentNode = AcpiGbl_RootNode; 622118611Snjl if (WalkState->ScopeInfo) 623118611Snjl { 624118611Snjl CurrentNode = WalkState->ScopeInfo->Scope.Node; 625118611Snjl } 626118611Snjl 627118611Snjl if (Flags & (AML_NAMED | AML_CREATE)) 628118611Snjl { 629118611Snjl /* This is the declaration of a new name */ 630118611Snjl 631281075Sdim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "NAME\n")); 632118611Snjl 633151937Sjkim /* 634240716Sjkim * The node of interest is the parent of this node (the containing 635240716Sjkim * scope). The actual namespace node may be up more than one level 636240716Sjkim * of parse op or it may not exist at all (if we traverse back 637240716Sjkim * up to the root.) 638151937Sjkim */ 639240716Sjkim NextOp = Op->Asl.Parent; 640240716Sjkim while (NextOp && (!NextOp->Asl.Node)) 641118611Snjl { 642240716Sjkim NextOp = NextOp->Asl.Parent; 643240716Sjkim } 644306536Sjkim 645240716Sjkim if (NextOp && NextOp->Asl.Node) 646240716Sjkim { 647240716Sjkim CurrentNode = NextOp->Asl.Node; 648240716Sjkim } 649240716Sjkim else 650240716Sjkim { 651118611Snjl CurrentNode = AcpiGbl_RootNode; 652118611Snjl } 653118611Snjl } 654118611Snjl else 655118611Snjl { 656118611Snjl /* This is a reference to an existing named object */ 657118611Snjl 658281075Sdim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "REFERENCE\n")); 659118611Snjl } 660118611Snjl 661118611Snjl /* 662118611Snjl * Obtain the full paths to the two nodes that we are interested in 663118611Snjl * (Target and current namespace location) in external 664118611Snjl * format -- something we can easily manipulate 665118611Snjl */ 666118611Snjl TargetPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 667306536Sjkim Status = AcpiNsHandleToPathname (TargetNode, &TargetPath, FALSE); 668118611Snjl if (ACPI_FAILURE (Status)) 669118611Snjl { 670151937Sjkim AslCoreSubsystemError (Op, Status, "Getting Target NamePath", 671151937Sjkim ASL_NO_ABORT); 672118611Snjl return_VOID; 673118611Snjl } 674306536Sjkim 675118611Snjl TargetPath.Length--; /* Subtract one for null terminator */ 676118611Snjl 677118611Snjl /* CurrentPath is the path to this scope (where we are in the namespace) */ 678118611Snjl 679118611Snjl CurrentPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 680306536Sjkim Status = AcpiNsHandleToPathname (CurrentNode, &CurrentPath, FALSE); 681118611Snjl if (ACPI_FAILURE (Status)) 682118611Snjl { 683151937Sjkim AslCoreSubsystemError (Op, Status, "Getting Current NamePath", 684151937Sjkim ASL_NO_ABORT); 685118611Snjl return_VOID; 686118611Snjl } 687306536Sjkim 688118611Snjl CurrentPath.Length--; /* Subtract one for null terminator */ 689118611Snjl 690118611Snjl /* Debug output only */ 691118611Snjl 692118611Snjl Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, AmlNameString, 693306536Sjkim NULL, &ExternalNameString); 694118611Snjl if (ACPI_FAILURE (Status)) 695118611Snjl { 696151937Sjkim AslCoreSubsystemError (Op, Status, "Externalizing NamePath", 697151937Sjkim ASL_NO_ABORT); 698118611Snjl return_VOID; 699118611Snjl } 700118611Snjl 701118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 702281075Sdim "CURRENT SCOPE: (%2u) %-37s FULL PATH TO NAME: (%2u) %-32s ACTUAL AML:%-32s\n", 703281075Sdim (UINT32) CurrentPath.Length, (char *) CurrentPath.Pointer, 704281075Sdim (UINT32) TargetPath.Length, (char *) TargetPath.Pointer, 705281075Sdim ExternalNameString)); 706118611Snjl 707167802Sjkim ACPI_FREE (ExternalNameString); 708118611Snjl 709118611Snjl /* 710118611Snjl * Attempt an optmization depending on the type of namepath 711118611Snjl */ 712118611Snjl if (Flags & (AML_NAMED | AML_CREATE)) 713118611Snjl { 714118611Snjl /* 715118611Snjl * This is a named opcode and the namepath is a name declaration, not 716118611Snjl * a reference. 717118611Snjl */ 718118611Snjl Status = OptOptimizeNameDeclaration (Op, WalkState, CurrentNode, 719306536Sjkim TargetNode, AmlNameString, &NewPath); 720118611Snjl if (ACPI_FAILURE (Status)) 721118611Snjl { 722118611Snjl /* 723118611Snjl * 2) now attempt to 724118611Snjl * optimize the namestring with carats (up-arrow) 725118611Snjl */ 726118611Snjl Status = OptBuildShortestPath (Op, WalkState, CurrentNode, 727306536Sjkim TargetNode, &CurrentPath, &TargetPath, 728306536Sjkim AmlNameStringLength, 1, &NewPath); 729118611Snjl } 730118611Snjl } 731118611Snjl else 732118611Snjl { 733118611Snjl /* 734118611Snjl * This is a reference to an existing named object 735118611Snjl * 736118611Snjl * 1) Check if search-to-root can be utilized using the last 737118611Snjl * NameSeg of the NamePath 738118611Snjl */ 739118611Snjl Status = OptSearchToRoot (Op, WalkState, CurrentNode, 740306536Sjkim TargetNode, &TargetPath, &NewPath); 741118611Snjl if (ACPI_FAILURE (Status)) 742118611Snjl { 743118611Snjl /* 744118611Snjl * 2) Search-to-root could not be used, now attempt to 745118611Snjl * optimize the namestring with carats (up-arrow) 746118611Snjl */ 747118611Snjl Status = OptBuildShortestPath (Op, WalkState, CurrentNode, 748306536Sjkim TargetNode, &CurrentPath, &TargetPath, 749306536Sjkim AmlNameStringLength, 0, &NewPath); 750118611Snjl } 751118611Snjl } 752118611Snjl 753118611Snjl /* 754118611Snjl * Success from above indicates that the NamePath was successfully 755241973Sjkim * optimized. We need to update the parse op with the new name 756118611Snjl */ 757118611Snjl if (ACPI_SUCCESS (Status)) 758118611Snjl { 759306536Sjkim HowMuchShorter = (AmlNameStringLength - strlen (NewPath)); 760118611Snjl OptTotal += HowMuchShorter; 761118611Snjl 762281075Sdim ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, 763281075Sdim " REDUCED BY %2u (TOTAL SAVED %2u)", 764193529Sjkim (UINT32) HowMuchShorter, OptTotal)); 765118611Snjl 766118611Snjl if (Flags & AML_NAMED) 767118611Snjl { 768118611Snjl if (Op->Asl.AmlOpcode == AML_ALIAS_OP) 769118611Snjl { 770118611Snjl /* 771118611Snjl * ALIAS is the only oddball opcode, the name declaration 772118611Snjl * (alias name) is the second operand 773118611Snjl */ 774118611Snjl Op->Asl.Child->Asl.Next->Asl.Value.String = NewPath; 775306536Sjkim Op->Asl.Child->Asl.Next->Asl.AmlLength = strlen (NewPath); 776118611Snjl } 777118611Snjl else 778118611Snjl { 779118611Snjl Op->Asl.Child->Asl.Value.String = NewPath; 780306536Sjkim Op->Asl.Child->Asl.AmlLength = strlen (NewPath); 781118611Snjl } 782118611Snjl } 783118611Snjl else if (Flags & AML_CREATE) 784118611Snjl { 785118611Snjl /* Name must appear as the last parameter */ 786118611Snjl 787118611Snjl NextOp = Op->Asl.Child; 788118611Snjl while (!(NextOp->Asl.CompileFlags & NODE_IS_NAME_DECLARATION)) 789118611Snjl { 790118611Snjl NextOp = NextOp->Asl.Next; 791118611Snjl } 792118611Snjl /* Update the parse node with the new NamePath */ 793118611Snjl 794118611Snjl NextOp->Asl.Value.String = NewPath; 795306536Sjkim NextOp->Asl.AmlLength = strlen (NewPath); 796118611Snjl } 797118611Snjl else 798118611Snjl { 799118611Snjl /* Update the parse node with the new NamePath */ 800118611Snjl 801118611Snjl Op->Asl.Value.String = NewPath; 802306536Sjkim Op->Asl.AmlLength = strlen (NewPath); 803118611Snjl } 804118611Snjl } 805118611Snjl else 806118611Snjl { 807118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, " ALREADY OPTIMAL")); 808118611Snjl } 809118611Snjl 810118611Snjl /* Cleanup path buffers */ 811118611Snjl 812167802Sjkim ACPI_FREE (TargetPath.Pointer); 813167802Sjkim ACPI_FREE (CurrentPath.Pointer); 814118611Snjl 815118611Snjl ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OPTIMIZATIONS, "\n")); 816118611Snjl return_VOID; 817118611Snjl} 818