1274357Sjkim/*******************************************************************************
2274357Sjkim *
3274357Sjkim * Module Name: dmcstyle - Support for C-style operator disassembly
4274357Sjkim *
5274357Sjkim ******************************************************************************/
6274357Sjkim
7274357Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
9274357Sjkim * All rights reserved.
10274357Sjkim *
11274357Sjkim * Redistribution and use in source and binary forms, with or without
12274357Sjkim * modification, are permitted provided that the following conditions
13274357Sjkim * are met:
14274357Sjkim * 1. Redistributions of source code must retain the above copyright
15274357Sjkim *    notice, this list of conditions, and the following disclaimer,
16274357Sjkim *    without modification.
17274357Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18274357Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19274357Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20274357Sjkim *    including a substantially similar Disclaimer requirement for further
21274357Sjkim *    binary redistribution.
22274357Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23274357Sjkim *    of any contributors may be used to endorse or promote products derived
24274357Sjkim *    from this software without specific prior written permission.
25274357Sjkim *
26274357Sjkim * Alternatively, this software may be distributed under the terms of the
27274357Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28274357Sjkim * Software Foundation.
29274357Sjkim *
30274357Sjkim * NO WARRANTY
31274357Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32274357Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33274357Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34274357Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35274357Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36274357Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37274357Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38274357Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39274357Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40274357Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41274357Sjkim * POSSIBILITY OF SUCH DAMAGES.
42274357Sjkim */
43274357Sjkim
44278970Sjkim#include <contrib/dev/acpica/include/acpi.h>
45278970Sjkim#include <contrib/dev/acpica/include/accommon.h>
46278970Sjkim#include <contrib/dev/acpica/include/acparser.h>
47278970Sjkim#include <contrib/dev/acpica/include/amlcode.h>
48278970Sjkim#include <contrib/dev/acpica/include/acdebug.h>
49274357Sjkim
50274357Sjkim
51274357Sjkim#define _COMPONENT          ACPI_CA_DEBUGGER
52274357Sjkim        ACPI_MODULE_NAME    ("dmcstyle")
53274357Sjkim
54274357Sjkim
55274357Sjkim/* Local prototypes */
56274357Sjkim
57274357Sjkimstatic char *
58274357SjkimAcpiDmGetCompoundSymbol (
59274357Sjkim   UINT16                   AslOpcode);
60274357Sjkim
61274357Sjkimstatic void
62274357SjkimAcpiDmPromoteTarget (
63274357Sjkim    ACPI_PARSE_OBJECT       *Op,
64274357Sjkim    ACPI_PARSE_OBJECT       *Target);
65274357Sjkim
66274357Sjkimstatic BOOLEAN
67274357SjkimAcpiDmIsValidTarget (
68274357Sjkim    ACPI_PARSE_OBJECT       *Op);
69274357Sjkim
70274357Sjkimstatic BOOLEAN
71274357SjkimAcpiDmIsTargetAnOperand (
72274357Sjkim    ACPI_PARSE_OBJECT       *Target,
73274357Sjkim    ACPI_PARSE_OBJECT       *Operand,
74274357Sjkim    BOOLEAN                 TopLevel);
75274357Sjkim
76274357Sjkim
77274357Sjkim/*******************************************************************************
78274357Sjkim *
79274357Sjkim * FUNCTION:    AcpiDmCheckForSymbolicOpcode
80274357Sjkim *
81274357Sjkim * PARAMETERS:  Op                  - Current parse object
82274357Sjkim *              Walk                - Current parse tree walk info
83274357Sjkim *
84274357Sjkim * RETURN:      TRUE if opcode can be converted to symbolic, FALSE otherwise
85274357Sjkim *
86274357Sjkim * DESCRIPTION: This is the main code that implements disassembly of AML code
87274357Sjkim *              to C-style operators. Called during descending phase of the
88274357Sjkim *              parse tree walk.
89274357Sjkim *
90274357Sjkim ******************************************************************************/
91274357Sjkim
92274357SjkimBOOLEAN
93274357SjkimAcpiDmCheckForSymbolicOpcode (
94274357Sjkim    ACPI_PARSE_OBJECT       *Op,
95274357Sjkim    ACPI_OP_WALK_INFO       *Info)
96274357Sjkim{
97274357Sjkim    char                    *OperatorSymbol = NULL;
98274357Sjkim    ACPI_PARSE_OBJECT       *Child1;
99274357Sjkim    ACPI_PARSE_OBJECT       *Child2;
100274357Sjkim    ACPI_PARSE_OBJECT       *Target;
101274357Sjkim
102274357Sjkim
103274357Sjkim    /* Exit immediately if ASL+ not enabled */
104274357Sjkim
105274357Sjkim    if (!AcpiGbl_CstyleDisassembly)
106274357Sjkim    {
107274357Sjkim        return (FALSE);
108274357Sjkim    }
109274357Sjkim
110274357Sjkim    /* Get the first operand */
111274357Sjkim
112274357Sjkim    Child1 = AcpiPsGetArg (Op, 0);
113274357Sjkim    if (!Child1)
114274357Sjkim    {
115274357Sjkim        return (FALSE);
116274357Sjkim    }
117274357Sjkim
118274357Sjkim    /* Get the second operand */
119274357Sjkim
120274357Sjkim    Child2 = Child1->Common.Next;
121274357Sjkim
122274357Sjkim    /* Setup the operator string for this opcode */
123274357Sjkim
124274357Sjkim    switch (Op->Common.AmlOpcode)
125274357Sjkim    {
126274357Sjkim    case AML_ADD_OP:
127274357Sjkim        OperatorSymbol = " + ";
128274357Sjkim        break;
129274357Sjkim
130274357Sjkim    case AML_SUBTRACT_OP:
131274357Sjkim        OperatorSymbol = " - ";
132274357Sjkim        break;
133274357Sjkim
134274357Sjkim    case AML_MULTIPLY_OP:
135274357Sjkim        OperatorSymbol = " * ";
136274357Sjkim        break;
137274357Sjkim
138274357Sjkim    case AML_DIVIDE_OP:
139274357Sjkim        OperatorSymbol = " / ";
140274357Sjkim        break;
141274357Sjkim
142274357Sjkim    case AML_MOD_OP:
143274357Sjkim        OperatorSymbol = " % ";
144274357Sjkim        break;
145274357Sjkim
146274357Sjkim    case AML_SHIFT_LEFT_OP:
147274357Sjkim        OperatorSymbol = " << ";
148274357Sjkim        break;
149274357Sjkim
150274357Sjkim    case AML_SHIFT_RIGHT_OP:
151274357Sjkim        OperatorSymbol = " >> ";
152274357Sjkim        break;
153274357Sjkim
154274357Sjkim    case AML_BIT_AND_OP:
155274357Sjkim        OperatorSymbol = " & ";
156274357Sjkim        break;
157274357Sjkim
158274357Sjkim    case AML_BIT_OR_OP:
159274357Sjkim        OperatorSymbol = " | ";
160274357Sjkim        break;
161274357Sjkim
162274357Sjkim    case AML_BIT_XOR_OP:
163274357Sjkim        OperatorSymbol = " ^ ";
164274357Sjkim        break;
165274357Sjkim
166274357Sjkim    /* Logical operators, no target */
167274357Sjkim
168274357Sjkim    case AML_LAND_OP:
169274357Sjkim        OperatorSymbol = " && ";
170274357Sjkim        break;
171274357Sjkim
172274357Sjkim    case AML_LEQUAL_OP:
173274357Sjkim        OperatorSymbol = " == ";
174274357Sjkim        break;
175274357Sjkim
176274357Sjkim    case AML_LGREATER_OP:
177274357Sjkim        OperatorSymbol = " > ";
178274357Sjkim        break;
179274357Sjkim
180274357Sjkim    case AML_LLESS_OP:
181274357Sjkim        OperatorSymbol = " < ";
182274357Sjkim        break;
183274357Sjkim
184274357Sjkim    case AML_LOR_OP:
185274357Sjkim        OperatorSymbol = " || ";
186274357Sjkim        break;
187274357Sjkim
188274357Sjkim    case AML_LNOT_OP:
189274357Sjkim        /*
190274357Sjkim         * Check for the LNOT sub-opcodes. These correspond to
191274357Sjkim         * LNotEqual, LLessEqual, and LGreaterEqual. There are
192274357Sjkim         * no actual AML opcodes for these operators.
193274357Sjkim         */
194274357Sjkim        switch (Child1->Common.AmlOpcode)
195274357Sjkim        {
196274357Sjkim        case AML_LEQUAL_OP:
197274357Sjkim            OperatorSymbol = " != ";
198274357Sjkim            break;
199274357Sjkim
200274357Sjkim        case AML_LGREATER_OP:
201274357Sjkim            OperatorSymbol = " <= ";
202274357Sjkim            break;
203274357Sjkim
204274357Sjkim        case AML_LLESS_OP:
205274357Sjkim            OperatorSymbol = " >= ";
206274357Sjkim            break;
207274357Sjkim
208274357Sjkim        default:
209274357Sjkim
210274357Sjkim            /* Unary LNOT case, emit "!" immediately */
211274357Sjkim
212274357Sjkim            AcpiOsPrintf ("!");
213274357Sjkim            return (TRUE);
214274357Sjkim        }
215274357Sjkim
216274357Sjkim        Child1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
217274357Sjkim        Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
218306536Sjkim        Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
219274357Sjkim
220274357Sjkim        /* Save symbol string in the next child (not peer) */
221274357Sjkim
222274357Sjkim        Child2 = AcpiPsGetArg (Child1, 0);
223274357Sjkim        if (!Child2)
224274357Sjkim        {
225274357Sjkim            return (FALSE);
226274357Sjkim        }
227274357Sjkim
228274357Sjkim        Child2->Common.OperatorSymbol = OperatorSymbol;
229274357Sjkim        return (TRUE);
230274357Sjkim
231274357Sjkim    case AML_INDEX_OP:
232306536Sjkim        /*
233306536Sjkim         * Check for constant source operand. Note: although technically
234306536Sjkim         * legal syntax, the iASL compiler does not support this with
235306536Sjkim         * the symbolic operators for Index(). It doesn't make sense to
236306536Sjkim         * use Index() with a constant anyway.
237306536Sjkim         */
238306536Sjkim        if ((Child1->Common.AmlOpcode == AML_STRING_OP)  ||
239306536Sjkim            (Child1->Common.AmlOpcode == AML_BUFFER_OP)  ||
240306536Sjkim            (Child1->Common.AmlOpcode == AML_PACKAGE_OP) ||
241306536Sjkim            (Child1->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
242306536Sjkim        {
243306536Sjkim            Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
244306536Sjkim            return (FALSE);
245306536Sjkim        }
246306536Sjkim
247306536Sjkim        /* Index operator is [] */
248306536Sjkim
249274357Sjkim        Child1->Common.OperatorSymbol = " [";
250274357Sjkim        Child2->Common.OperatorSymbol = "]";
251274357Sjkim        break;
252274357Sjkim
253274357Sjkim    /* Unary operators */
254274357Sjkim
255274357Sjkim    case AML_DECREMENT_OP:
256274357Sjkim        OperatorSymbol = "--";
257274357Sjkim        break;
258274357Sjkim
259274357Sjkim    case AML_INCREMENT_OP:
260274357Sjkim        OperatorSymbol = "++";
261274357Sjkim        break;
262274357Sjkim
263274357Sjkim    case AML_BIT_NOT_OP:
264274357Sjkim    case AML_STORE_OP:
265274357Sjkim        OperatorSymbol = NULL;
266274357Sjkim        break;
267274357Sjkim
268274357Sjkim    default:
269274357Sjkim        return (FALSE);
270274357Sjkim    }
271274357Sjkim
272274357Sjkim    if (Child1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
273274357Sjkim    {
274274357Sjkim        return (TRUE);
275274357Sjkim    }
276274357Sjkim
277274357Sjkim    /*
278274357Sjkim     * This is the key to how the disassembly of the C-style operators
279274357Sjkim     * works. We save the operator symbol in the first child, thus
280274357Sjkim     * deferring symbol output until after the first operand has been
281274357Sjkim     * emitted.
282274357Sjkim     */
283274357Sjkim    if (!Child1->Common.OperatorSymbol)
284274357Sjkim    {
285274357Sjkim        Child1->Common.OperatorSymbol = OperatorSymbol;
286274357Sjkim    }
287274357Sjkim
288274357Sjkim    /*
289274357Sjkim     * Check for a valid target as the 3rd (or sometimes 2nd) operand
290274357Sjkim     *
291274357Sjkim     * Compound assignment operator support:
292274357Sjkim     * Attempt to optimize constructs of the form:
293274357Sjkim     *      Add (Local1, 0xFF, Local1)
294274357Sjkim     * to:
295274357Sjkim     *      Local1 += 0xFF
296274357Sjkim     *
297274357Sjkim     * Only the math operators and Store() have a target.
298274357Sjkim     * Logicals have no target.
299274357Sjkim     */
300274357Sjkim    switch (Op->Common.AmlOpcode)
301274357Sjkim    {
302274357Sjkim    case AML_ADD_OP:
303274357Sjkim    case AML_SUBTRACT_OP:
304274357Sjkim    case AML_MULTIPLY_OP:
305274357Sjkim    case AML_DIVIDE_OP:
306274357Sjkim    case AML_MOD_OP:
307274357Sjkim    case AML_SHIFT_LEFT_OP:
308274357Sjkim    case AML_SHIFT_RIGHT_OP:
309274357Sjkim    case AML_BIT_AND_OP:
310274357Sjkim    case AML_BIT_OR_OP:
311274357Sjkim    case AML_BIT_XOR_OP:
312274357Sjkim
313274357Sjkim        /* Target is 3rd operand */
314274357Sjkim
315274357Sjkim        Target = Child2->Common.Next;
316274357Sjkim        if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
317274357Sjkim        {
318274357Sjkim            /*
319274357Sjkim             * Divide has an extra target operand (Remainder).
320274357Sjkim             * If this extra target is specified, it cannot be converted
321274357Sjkim             * to a C-style operator
322274357Sjkim             */
323274357Sjkim            if (AcpiDmIsValidTarget (Target))
324274357Sjkim            {
325274357Sjkim                Child1->Common.OperatorSymbol = NULL;
326274357Sjkim                return (FALSE);
327274357Sjkim            }
328274357Sjkim
329274357Sjkim            Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
330274357Sjkim            Target = Target->Common.Next;
331274357Sjkim        }
332274357Sjkim
333274357Sjkim        /* Parser should ensure there is at least a placeholder target */
334274357Sjkim
335274357Sjkim        if (!Target)
336274357Sjkim        {
337274357Sjkim            return (FALSE);
338274357Sjkim        }
339274357Sjkim
340274357Sjkim        if (!AcpiDmIsValidTarget (Target))
341274357Sjkim        {
342274357Sjkim            /* Not a valid target (placeholder only, from parser) */
343274357Sjkim            break;
344274357Sjkim        }
345274357Sjkim
346274357Sjkim        /*
347274357Sjkim         * Promote the target up to the first child in the parse
348274357Sjkim         * tree. This is done because the target will be output
349274357Sjkim         * first, in the form:
350274357Sjkim         *     <Target> = Operands...
351274357Sjkim         */
352274357Sjkim        AcpiDmPromoteTarget (Op, Target);
353274357Sjkim
354306536Sjkim        /* Check operands for conversion to a "Compound Assignment" */
355306536Sjkim
356306536Sjkim        switch (Op->Common.AmlOpcode)
357274357Sjkim        {
358306536Sjkim            /* Commutative operators */
359274357Sjkim
360306536Sjkim        case AML_ADD_OP:
361306536Sjkim        case AML_MULTIPLY_OP:
362306536Sjkim        case AML_BIT_AND_OP:
363306536Sjkim        case AML_BIT_OR_OP:
364306536Sjkim        case AML_BIT_XOR_OP:
365306536Sjkim            /*
366306536Sjkim             * For the commutative operators, we can convert to a
367306536Sjkim             * compound statement only if at least one (either) operand
368306536Sjkim             * is the same as the target.
369306536Sjkim             *
370306536Sjkim             *      Add (A, B, A) --> A += B
371306536Sjkim             *      Add (B, A, A) --> A += B
372306536Sjkim             *      Add (B, C, A) --> A = (B + C)
373306536Sjkim             */
374306536Sjkim            if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) ||
375306536Sjkim                (AcpiDmIsTargetAnOperand (Target, Child2, TRUE)))
376306536Sjkim            {
377306536Sjkim                Target->Common.OperatorSymbol =
378306536Sjkim                    AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
379274357Sjkim
380306536Sjkim                /* Convert operator to compound assignment */
381306536Sjkim
382306536Sjkim                Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
383306536Sjkim                Child1->Common.OperatorSymbol = NULL;
384306536Sjkim                return (TRUE);
385306536Sjkim            }
386306536Sjkim            break;
387306536Sjkim
388306536Sjkim            /* Non-commutative operators */
389306536Sjkim
390306536Sjkim        case AML_SUBTRACT_OP:
391306536Sjkim        case AML_DIVIDE_OP:
392306536Sjkim        case AML_MOD_OP:
393306536Sjkim        case AML_SHIFT_LEFT_OP:
394306536Sjkim        case AML_SHIFT_RIGHT_OP:
395306536Sjkim            /*
396306536Sjkim             * For the non-commutative operators, we can convert to a
397306536Sjkim             * compound statement only if the target is the same as the
398306536Sjkim             * first operand.
399306536Sjkim             *
400306536Sjkim             *      Subtract (A, B, A) --> A -= B
401306536Sjkim             *      Subtract (B, A, A) --> A = (B - A)
402306536Sjkim             */
403306536Sjkim            if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)))
404306536Sjkim            {
405306536Sjkim                Target->Common.OperatorSymbol =
406306536Sjkim                    AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
407306536Sjkim
408306536Sjkim                /* Convert operator to compound assignment */
409306536Sjkim
410306536Sjkim                Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
411306536Sjkim                Child1->Common.OperatorSymbol = NULL;
412306536Sjkim                return (TRUE);
413306536Sjkim            }
414306536Sjkim            break;
415306536Sjkim
416306536Sjkim        default:
417306536Sjkim            break;
418274357Sjkim        }
419274357Sjkim
420274357Sjkim        /*
421274357Sjkim         * If we are within a C-style expression, emit an extra open
422274357Sjkim         * paren. Implemented by examining the parent op.
423274357Sjkim         */
424274357Sjkim        switch (Op->Common.Parent->Common.AmlOpcode)
425274357Sjkim        {
426274357Sjkim        case AML_ADD_OP:
427274357Sjkim        case AML_SUBTRACT_OP:
428274357Sjkim        case AML_MULTIPLY_OP:
429274357Sjkim        case AML_DIVIDE_OP:
430274357Sjkim        case AML_MOD_OP:
431274357Sjkim        case AML_SHIFT_LEFT_OP:
432274357Sjkim        case AML_SHIFT_RIGHT_OP:
433274357Sjkim        case AML_BIT_AND_OP:
434274357Sjkim        case AML_BIT_OR_OP:
435274357Sjkim        case AML_BIT_XOR_OP:
436274357Sjkim        case AML_LAND_OP:
437274357Sjkim        case AML_LEQUAL_OP:
438274357Sjkim        case AML_LGREATER_OP:
439274357Sjkim        case AML_LLESS_OP:
440274357Sjkim        case AML_LOR_OP:
441274357Sjkim
442274357Sjkim            Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
443274357Sjkim            AcpiOsPrintf ("(");
444274357Sjkim            break;
445274357Sjkim
446274357Sjkim        default:
447274357Sjkim            break;
448274357Sjkim        }
449274357Sjkim
450274357Sjkim        /* Normal output for ASL/AML operators with a target operand */
451274357Sjkim
452274357Sjkim        Target->Common.OperatorSymbol = " = (";
453274357Sjkim        return (TRUE);
454274357Sjkim
455274357Sjkim    /* Binary operators, no parens */
456274357Sjkim
457274357Sjkim    case AML_DECREMENT_OP:
458274357Sjkim    case AML_INCREMENT_OP:
459274357Sjkim        return (TRUE);
460274357Sjkim
461274357Sjkim    case AML_INDEX_OP:
462274357Sjkim
463274357Sjkim        /* Target is optional, 3rd operand */
464274357Sjkim
465274357Sjkim        Target = Child2->Common.Next;
466274357Sjkim        if (AcpiDmIsValidTarget (Target))
467274357Sjkim        {
468274357Sjkim            AcpiDmPromoteTarget (Op, Target);
469274357Sjkim
470274357Sjkim            if (!Target->Common.OperatorSymbol)
471274357Sjkim            {
472274357Sjkim                Target->Common.OperatorSymbol = " = ";
473274357Sjkim            }
474274357Sjkim        }
475274357Sjkim        return (TRUE);
476274357Sjkim
477274357Sjkim    case AML_STORE_OP:
478274357Sjkim        /*
479274357Sjkim         * Target is the 2nd operand.
480274357Sjkim         * We know the target is valid, it is not optional.
481274357Sjkim         * In the parse tree, simply swap the target with the
482274357Sjkim         * source so that the target is processed first.
483274357Sjkim         */
484274357Sjkim        Target = Child1->Common.Next;
485306536Sjkim        if (!Target)
486306536Sjkim        {
487306536Sjkim            return (FALSE);
488306536Sjkim        }
489306536Sjkim
490274357Sjkim        AcpiDmPromoteTarget (Op, Target);
491274357Sjkim        if (!Target->Common.OperatorSymbol)
492274357Sjkim        {
493274357Sjkim            Target->Common.OperatorSymbol = " = ";
494274357Sjkim        }
495274357Sjkim        return (TRUE);
496274357Sjkim
497274357Sjkim    case AML_BIT_NOT_OP:
498274357Sjkim
499274357Sjkim        /* Target is optional, 2nd operand */
500274357Sjkim
501274357Sjkim        Target = Child1->Common.Next;
502274357Sjkim        if (!Target)
503274357Sjkim        {
504274357Sjkim            return (FALSE);
505274357Sjkim        }
506274357Sjkim
507274357Sjkim        if (AcpiDmIsValidTarget (Target))
508274357Sjkim        {
509274357Sjkim            /* Valid target, not a placeholder */
510274357Sjkim
511274357Sjkim            AcpiDmPromoteTarget (Op, Target);
512274357Sjkim            Target->Common.OperatorSymbol = " = ~";
513274357Sjkim        }
514274357Sjkim        else
515274357Sjkim        {
516274357Sjkim            /* No target. Emit this prefix operator immediately */
517274357Sjkim
518274357Sjkim            AcpiOsPrintf ("~");
519274357Sjkim        }
520274357Sjkim        return (TRUE);
521274357Sjkim
522274357Sjkim    default:
523274357Sjkim        break;
524274357Sjkim    }
525274357Sjkim
526306536Sjkim    /*
527306536Sjkim     * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens
528306536Sjkim     * output here. We also need to check the parent to see if this op
529306536Sjkim     * is part of a compound test (!=, >=, <=).
530306536Sjkim     */
531306536Sjkim    if ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) ||
532306536Sjkim       ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) &&
533306536Sjkim        (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)))
534306536Sjkim    {
535306536Sjkim        /* Do Nothing. Paren already generated */
536306536Sjkim        return (TRUE);
537306536Sjkim    }
538306536Sjkim
539274357Sjkim    /* All other operators, emit an open paren */
540274357Sjkim
541274357Sjkim    AcpiOsPrintf ("(");
542274357Sjkim    return (TRUE);
543274357Sjkim}
544274357Sjkim
545274357Sjkim
546274357Sjkim/*******************************************************************************
547274357Sjkim *
548274357Sjkim * FUNCTION:    AcpiDmCloseOperator
549274357Sjkim *
550274357Sjkim * PARAMETERS:  Op                  - Current parse object
551274357Sjkim *
552274357Sjkim * RETURN:      None
553274357Sjkim *
554274357Sjkim * DESCRIPTION: Closes an operator by adding a closing parentheses if and
555274357Sjkim *              when necessary. Called during ascending phase of the
556274357Sjkim *              parse tree walk.
557274357Sjkim *
558274357Sjkim ******************************************************************************/
559274357Sjkim
560274357Sjkimvoid
561274357SjkimAcpiDmCloseOperator (
562274357Sjkim    ACPI_PARSE_OBJECT       *Op)
563274357Sjkim{
564306536Sjkim    BOOLEAN                 IsCStyleOp = FALSE;
565274357Sjkim
566274357Sjkim    /* Always emit paren if ASL+ disassembly disabled */
567274357Sjkim
568274357Sjkim    if (!AcpiGbl_CstyleDisassembly)
569274357Sjkim    {
570274357Sjkim        AcpiOsPrintf (")");
571274357Sjkim        return;
572274357Sjkim    }
573274357Sjkim
574274357Sjkim    /* Check if we need to add an additional closing paren */
575274357Sjkim
576274357Sjkim    switch (Op->Common.AmlOpcode)
577274357Sjkim    {
578274357Sjkim    case AML_ADD_OP:
579274357Sjkim    case AML_SUBTRACT_OP:
580274357Sjkim    case AML_MULTIPLY_OP:
581274357Sjkim    case AML_DIVIDE_OP:
582274357Sjkim    case AML_MOD_OP:
583274357Sjkim    case AML_SHIFT_LEFT_OP:
584274357Sjkim    case AML_SHIFT_RIGHT_OP:
585274357Sjkim    case AML_BIT_AND_OP:
586274357Sjkim    case AML_BIT_OR_OP:
587274357Sjkim    case AML_BIT_XOR_OP:
588274357Sjkim    case AML_LAND_OP:
589274357Sjkim    case AML_LEQUAL_OP:
590274357Sjkim    case AML_LGREATER_OP:
591274357Sjkim    case AML_LLESS_OP:
592274357Sjkim    case AML_LOR_OP:
593274357Sjkim
594274357Sjkim        /* Emit paren only if this is not a compound assignment */
595274357Sjkim
596306536Sjkim        if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT)
597274357Sjkim        {
598274357Sjkim            return;
599274357Sjkim        }
600274357Sjkim
601274357Sjkim        /* Emit extra close paren for assignment within an expression */
602274357Sjkim
603274357Sjkim        if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
604274357Sjkim        {
605274357Sjkim            AcpiOsPrintf (")");
606274357Sjkim        }
607306536Sjkim
608306536Sjkim        IsCStyleOp = TRUE;
609274357Sjkim        break;
610274357Sjkim
611306536Sjkim    case AML_INDEX_OP:
612274357Sjkim
613306536Sjkim        /* This is case for unsupported Index() source constants */
614306536Sjkim
615306536Sjkim        if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
616306536Sjkim        {
617306536Sjkim            AcpiOsPrintf (")");
618306536Sjkim        }
619306536Sjkim        return;
620306536Sjkim
621274357Sjkim    /* No need for parens for these */
622274357Sjkim
623274357Sjkim    case AML_DECREMENT_OP:
624274357Sjkim    case AML_INCREMENT_OP:
625274357Sjkim    case AML_LNOT_OP:
626274357Sjkim    case AML_BIT_NOT_OP:
627274357Sjkim    case AML_STORE_OP:
628274357Sjkim        return;
629274357Sjkim
630274357Sjkim    default:
631274357Sjkim
632274357Sjkim        /* Always emit paren for non-ASL+ operators */
633274357Sjkim        break;
634274357Sjkim    }
635274357Sjkim
636306536Sjkim    /*
637306536Sjkim     * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens
638306536Sjkim     * output here. We also need to check the parent to see if this op
639306536Sjkim     * is part of a compound test (!=, >=, <=).
640306536Sjkim     */
641306536Sjkim    if (IsCStyleOp &&
642306536Sjkim       ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) ||
643306536Sjkim       ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) &&
644306536Sjkim        (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX))))
645306536Sjkim    {
646306536Sjkim        return;
647306536Sjkim    }
648306536Sjkim
649274357Sjkim    AcpiOsPrintf (")");
650306536Sjkim    return;
651274357Sjkim}
652274357Sjkim
653274357Sjkim
654274357Sjkim/*******************************************************************************
655274357Sjkim *
656274357Sjkim * FUNCTION:    AcpiDmGetCompoundSymbol
657274357Sjkim *
658274357Sjkim * PARAMETERS:  AslOpcode
659274357Sjkim *
660274357Sjkim * RETURN:      String containing the compound assignment symbol
661274357Sjkim *
662274357Sjkim * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
663274357Sjkim *              return the appropriate operator string.
664274357Sjkim *
665274357Sjkim ******************************************************************************/
666274357Sjkim
667274357Sjkimstatic char *
668274357SjkimAcpiDmGetCompoundSymbol (
669274357Sjkim   UINT16                   AmlOpcode)
670274357Sjkim{
671274357Sjkim    char                    *Symbol;
672274357Sjkim
673274357Sjkim
674274357Sjkim    switch (AmlOpcode)
675274357Sjkim    {
676274357Sjkim    case AML_ADD_OP:
677274357Sjkim        Symbol = " += ";
678274357Sjkim        break;
679274357Sjkim
680274357Sjkim    case AML_SUBTRACT_OP:
681274357Sjkim        Symbol = " -= ";
682274357Sjkim        break;
683274357Sjkim
684274357Sjkim    case AML_MULTIPLY_OP:
685274357Sjkim        Symbol = " *= ";
686274357Sjkim        break;
687274357Sjkim
688274357Sjkim    case AML_DIVIDE_OP:
689274357Sjkim        Symbol = " /= ";
690274357Sjkim        break;
691274357Sjkim
692274357Sjkim    case AML_MOD_OP:
693274357Sjkim        Symbol = " %= ";
694274357Sjkim        break;
695274357Sjkim
696274357Sjkim    case AML_SHIFT_LEFT_OP:
697274357Sjkim        Symbol = " <<= ";
698274357Sjkim        break;
699274357Sjkim
700274357Sjkim    case AML_SHIFT_RIGHT_OP:
701274357Sjkim        Symbol = " >>= ";
702274357Sjkim        break;
703274357Sjkim
704274357Sjkim    case AML_BIT_AND_OP:
705274357Sjkim        Symbol = " &= ";
706274357Sjkim        break;
707274357Sjkim
708274357Sjkim    case AML_BIT_OR_OP:
709274357Sjkim        Symbol = " |= ";
710274357Sjkim        break;
711274357Sjkim
712274357Sjkim    case AML_BIT_XOR_OP:
713274357Sjkim        Symbol = " ^= ";
714274357Sjkim        break;
715274357Sjkim
716274357Sjkim    default:
717274357Sjkim
718274357Sjkim        /* No operator string for all other opcodes */
719306536Sjkim
720274357Sjkim        return (NULL);
721274357Sjkim    }
722274357Sjkim
723274357Sjkim    return (Symbol);
724274357Sjkim}
725274357Sjkim
726274357Sjkim
727274357Sjkim/*******************************************************************************
728274357Sjkim *
729274357Sjkim * FUNCTION:    AcpiDmPromoteTarget
730274357Sjkim *
731274357Sjkim * PARAMETERS:  Op                  - Operator parse object
732274357Sjkim *              Target              - Target associate with the Op
733274357Sjkim *
734274357Sjkim * RETURN:      None
735274357Sjkim *
736274357Sjkim * DESCRIPTION: Transform the parse tree by moving the target up to the first
737274357Sjkim *              child of the Op.
738274357Sjkim *
739274357Sjkim ******************************************************************************/
740274357Sjkim
741274357Sjkimstatic void
742274357SjkimAcpiDmPromoteTarget (
743274357Sjkim    ACPI_PARSE_OBJECT       *Op,
744274357Sjkim    ACPI_PARSE_OBJECT       *Target)
745274357Sjkim{
746274357Sjkim    ACPI_PARSE_OBJECT       *Child;
747274357Sjkim
748274357Sjkim
749274357Sjkim    /* Link target directly to the Op as first child */
750274357Sjkim
751274357Sjkim    Child = Op->Common.Value.Arg;
752274357Sjkim    Op->Common.Value.Arg = Target;
753274357Sjkim    Target->Common.Next = Child;
754274357Sjkim
755274357Sjkim    /* Find the last peer, it is linked to the target. Unlink it. */
756274357Sjkim
757274357Sjkim    while (Child->Common.Next != Target)
758274357Sjkim    {
759274357Sjkim        Child = Child->Common.Next;
760274357Sjkim    }
761274357Sjkim
762274357Sjkim    Child->Common.Next = NULL;
763274357Sjkim}
764274357Sjkim
765274357Sjkim
766274357Sjkim/*******************************************************************************
767274357Sjkim *
768274357Sjkim * FUNCTION:    AcpiDmIsValidTarget
769274357Sjkim *
770274357Sjkim * PARAMETERS:  Target              - Target Op from the parse tree
771274357Sjkim *
772274357Sjkim * RETURN:      TRUE if the Target is real. FALSE if it is just a placeholder
773274357Sjkim *              Op that was inserted by the parser.
774274357Sjkim *
775274357Sjkim * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
776274357Sjkim *              In other words, determine if the optional target is used or
777306536Sjkim *              not. Note: If Target is NULL, something is seriously wrong,
778306536Sjkim *              probably with the parse tree.
779274357Sjkim *
780274357Sjkim ******************************************************************************/
781274357Sjkim
782274357Sjkimstatic BOOLEAN
783274357SjkimAcpiDmIsValidTarget (
784274357Sjkim    ACPI_PARSE_OBJECT       *Target)
785274357Sjkim{
786274357Sjkim
787306536Sjkim    if (!Target)
788306536Sjkim    {
789306536Sjkim        return (FALSE);
790306536Sjkim    }
791306536Sjkim
792274357Sjkim    if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
793274357Sjkim        (Target->Common.Value.Arg == NULL))
794274357Sjkim    {
795274357Sjkim        return (FALSE);
796274357Sjkim    }
797274357Sjkim
798274357Sjkim    return (TRUE);
799274357Sjkim}
800274357Sjkim
801274357Sjkim
802274357Sjkim/*******************************************************************************
803274357Sjkim *
804274357Sjkim * FUNCTION:    AcpiDmIsTargetAnOperand
805274357Sjkim *
806274357Sjkim * PARAMETERS:  Target              - Target associated with the expression
807274357Sjkim *              Operand             - An operand associated with expression
808274357Sjkim *
809274357Sjkim * RETURN:      TRUE if expression can be converted to a compound assignment.
810274357Sjkim *              FALSE otherwise.
811274357Sjkim *
812274357Sjkim * DESCRIPTION: Determine if the Target duplicates the operand, in order to
813274357Sjkim *              detect if the expression can be converted to a compound
814274357Sjkim *              assigment. (+=, *=, etc.)
815274357Sjkim *
816274357Sjkim ******************************************************************************/
817274357Sjkim
818274357Sjkimstatic BOOLEAN
819274357SjkimAcpiDmIsTargetAnOperand (
820274357Sjkim    ACPI_PARSE_OBJECT       *Target,
821274357Sjkim    ACPI_PARSE_OBJECT       *Operand,
822274357Sjkim    BOOLEAN                 TopLevel)
823274357Sjkim{
824274357Sjkim    const ACPI_OPCODE_INFO  *OpInfo;
825274357Sjkim    BOOLEAN                 Same;
826274357Sjkim
827274357Sjkim
828274357Sjkim    /*
829274357Sjkim     * Opcodes must match. Note: ignoring the difference between nameseg
830274357Sjkim     * and namepath for now. May be needed later.
831274357Sjkim     */
832274357Sjkim    if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
833274357Sjkim    {
834274357Sjkim        return (FALSE);
835274357Sjkim    }
836274357Sjkim
837274357Sjkim    /* Nodes should match, even if they are NULL */
838274357Sjkim
839274357Sjkim    if (Target->Common.Node != Operand->Common.Node)
840274357Sjkim    {
841274357Sjkim        return (FALSE);
842274357Sjkim    }
843274357Sjkim
844274357Sjkim    /* Determine if a child exists */
845274357Sjkim
846274357Sjkim    OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
847274357Sjkim    if (OpInfo->Flags & AML_HAS_ARGS)
848274357Sjkim    {
849274357Sjkim        Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
850274357Sjkim            Operand->Common.Value.Arg, FALSE);
851274357Sjkim        if (!Same)
852274357Sjkim        {
853274357Sjkim            return (FALSE);
854274357Sjkim        }
855274357Sjkim    }
856274357Sjkim
857274357Sjkim    /* Check the next peer, as long as we are not at the top level */
858274357Sjkim
859274357Sjkim    if ((!TopLevel) &&
860274357Sjkim         Target->Common.Next)
861274357Sjkim    {
862274357Sjkim        Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
863274357Sjkim            Operand->Common.Next, FALSE);
864274357Sjkim        if (!Same)
865274357Sjkim        {
866274357Sjkim            return (FALSE);
867274357Sjkim        }
868274357Sjkim    }
869274357Sjkim
870274357Sjkim    /* Supress the duplicate operand at the top-level */
871274357Sjkim
872274357Sjkim    if (TopLevel)
873274357Sjkim    {
874274357Sjkim        Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
875274357Sjkim    }
876274357Sjkim    return (TRUE);
877274357Sjkim}
878