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