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