From ffefc5e3087113df2119d5997226536583c659b3 Mon Sep 17 00:00:00 2001 From: Robert Moore Date: Fri, 3 Aug 2012 14:24:58 -0700 Subject: [PATCH] iASL: Fix constant folding for fixed-length constants. This change fixes a problem where the constant folding code was not invoked for arguments that compile to fixed-length constants (either Byte, Word, DWord, or QWord.) ACPICA BZ 970. --- source/compiler/aslcompiler.h | 5 ++ source/compiler/aslcompiler.y | 24 ++++--- source/compiler/aslfold.c | 129 +++++++++++++++++++++++++--------- source/compiler/aslmessages.h | 2 + source/compiler/asltree.c | 86 ++++++++++++++++------- source/compiler/aslutils.c | 29 +++----- 6 files changed, 189 insertions(+), 86 deletions(-) diff --git a/source/compiler/aslcompiler.h b/source/compiler/aslcompiler.h index 03303f593..b88d01076 100644 --- a/source/compiler/aslcompiler.h +++ b/source/compiler/aslcompiler.h @@ -665,6 +665,11 @@ TrSetNodeFlags ( ACPI_PARSE_OBJECT *Op, UINT32 Flags); +ACPI_PARSE_OBJECT * +TrSetNodeAmlLength ( + ACPI_PARSE_OBJECT *Op, + UINT32 Length); + ACPI_PARSE_OBJECT * TrLinkPeerNodes ( UINT32 NumPeers, diff --git a/source/compiler/aslcompiler.y b/source/compiler/aslcompiler.y index 4cff645dd..93872ff75 100644 --- a/source/compiler/aslcompiler.y +++ b/source/compiler/aslcompiler.y @@ -2579,30 +2579,38 @@ ConstExprTerm | PARSEOP___PATH__ {$$ = TrCreateConstantLeafNode (PARSEOP___PATH__);} ; +/* + * The NODE_COMPILE_TIME_CONST flag in the following constant expressions + * enables compile-time constant folding to reduce the Type3Opcodes/Type2IntegerOpcodes + * to simple integers. It is an error if these types of expressions cannot be + * reduced, since the AML grammar for ****ConstExpr requires a simple constant. + * Note: The required byte length of the constant is passed through to the + * constant folding code in the node AmlLength field. + */ ByteConstExpr - : Type3Opcode {$$ = TrUpdateNode (PARSEOP_BYTECONST, $1);} - | Type2IntegerOpcode {$$ = TrUpdateNode (PARSEOP_BYTECONST, $1);} + : Type3Opcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 1);} + | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 1);} | ConstExprTerm {$$ = TrUpdateNode (PARSEOP_BYTECONST, $1);} | ByteConst {} ; WordConstExpr - : Type3Opcode {$$ = TrUpdateNode (PARSEOP_WORDCONST, $1);} - | Type2IntegerOpcode {$$ = TrUpdateNode (PARSEOP_WORDCONST, $1);} + : Type3Opcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 2);} + | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 2);} | ConstExprTerm {$$ = TrUpdateNode (PARSEOP_WORDCONST, $1);} | WordConst {} ; DWordConstExpr - : Type3Opcode {$$ = TrUpdateNode (PARSEOP_DWORDCONST, $1);} - | Type2IntegerOpcode {$$ = TrUpdateNode (PARSEOP_DWORDCONST, $1);} + : Type3Opcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 4);} + | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 4);} | ConstExprTerm {$$ = TrUpdateNode (PARSEOP_DWORDCONST, $1);} | DWordConst {} ; QWordConstExpr - : Type3Opcode {$$ = TrUpdateNode (PARSEOP_QWORDCONST, $1);} - | Type2IntegerOpcode {$$ = TrUpdateNode (PARSEOP_QWORDCONST, $1);} + : Type3Opcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 8);} + | Type2IntegerOpcode {$$ = TrSetNodeFlags ($1, NODE_COMPILE_TIME_CONST); TrSetNodeAmlLength ($1, 8);} | ConstExprTerm {$$ = TrUpdateNode (PARSEOP_QWORDCONST, $1);} | QWordConst {} ; diff --git a/source/compiler/aslfold.c b/source/compiler/aslfold.c index dffcc574c..f750aa597 100644 --- a/source/compiler/aslfold.c +++ b/source/compiler/aslfold.c @@ -145,6 +145,11 @@ OpcAmlCheckForConstant ( UINT32 Level, void *Context); +static void +OpcUpdateIntegerNode ( + ACPI_PARSE_OBJECT *Op, + UINT64 Value); + /******************************************************************************* * @@ -286,14 +291,14 @@ OpcAmlCheckForConstant ( { /* * We are looking at at normal expression to see if it can be - * reduced. It can't. No error + * reduced. It can't. No error */ return (AE_TYPE); } /* * This is an expression that MUST reduce to a constant, and it - * can't be reduced. This is an error + * can't be reduced. This is an error */ if (Op->Asl.CompileFlags & NODE_IS_TARGET) { @@ -391,17 +396,17 @@ OpcAmlConstantWalk ( return AE_NO_MEMORY; } - WalkState->NextOp = NULL; - WalkState->Params = NULL; - WalkState->CallerReturnDesc = &ObjDesc; - WalkState->WalkType = WalkType; + WalkState->NextOp = NULL; + WalkState->Params = NULL; + WalkState->WalkType = WalkType; + WalkState->CallerReturnDesc = &ObjDesc; /* * Examine the entire subtree -- all nodes must be constants * or type 3/4/5 opcodes */ Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD, - OpcAmlCheckForConstant, NULL, WalkState); + OpcAmlCheckForConstant, NULL, WalkState); /* * Did we find an entire subtree that contains all constants and type 3/4/5 @@ -441,7 +446,7 @@ OpcAmlConstantWalk ( /* Hand off the subtree to the AML interpreter */ Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE, - OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState); + OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState); Op->Common.Parent = OriginalParentOp; /* TBD: we really *should* release the RootOp node */ @@ -454,22 +459,26 @@ OpcAmlConstantWalk ( Status = AcpiDsResultPop (&ObjDesc, WalkState); } + + /* Check for error from the ACPICA core */ + + if (ACPI_FAILURE (Status)) + { + AslCoreSubsystemError (Op, Status, + "Failure during constant evaluation", FALSE); + } } if (ACPI_FAILURE (Status)) { /* We could not resolve the subtree for some reason */ - AslCoreSubsystemError (Op, Status, - "Failure during constant evaluation", FALSE); AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op, Op->Asl.ParseOpName); - /* Set the subtree value to ZERO anyway. Eliminates further errors */ + /* Set the subtree value to ZERO anyway. Eliminates further errors */ - Op->Asl.ParseOpcode = PARSEOP_INTEGER; - Op->Common.Value.Integer = 0; - OpcSetOptimalIntegerSize (Op); + OpcUpdateIntegerNode (Op, 0); } else { @@ -484,21 +493,20 @@ OpcAmlConstantWalk ( { case ACPI_TYPE_INTEGER: - Op->Asl.ParseOpcode = PARSEOP_INTEGER; - Op->Common.Value.Integer = ObjDesc->Integer.Value; - OpcSetOptimalIntegerSize (Op); + OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value); DbgPrint (ASL_PARSE_OUTPUT, - "Constant expression reduced to (INTEGER) %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (ObjDesc->Integer.Value)); + "Constant expression reduced to (%s) %8.8X%8.8X\n", + Op->Asl.ParseOpName, + ACPI_FORMAT_UINT64 (Op->Common.Value.Integer)); break; case ACPI_TYPE_STRING: - Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL; - Op->Common.AmlOpcode = AML_STRING_OP; - Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1; + Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL; + Op->Common.AmlOpcode = AML_STRING_OP; + Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1; Op->Common.Value.String = ObjDesc->String.Pointer; DbgPrint (ASL_PARSE_OUTPUT, @@ -510,18 +518,18 @@ OpcAmlConstantWalk ( case ACPI_TYPE_BUFFER: - Op->Asl.ParseOpcode = PARSEOP_BUFFER; - Op->Common.AmlOpcode = AML_BUFFER_OP; - Op->Asl.CompileFlags = NODE_AML_PACKAGE; + Op->Asl.ParseOpcode = PARSEOP_BUFFER; + Op->Common.AmlOpcode = AML_BUFFER_OP; + Op->Asl.CompileFlags = NODE_AML_PACKAGE; UtSetParseOpName (Op); /* Child node is the buffer length */ RootOp = TrAllocateNode (PARSEOP_INTEGER); - RootOp->Asl.AmlOpcode = AML_DWORD_OP; + RootOp->Asl.AmlOpcode = AML_DWORD_OP; RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length; - RootOp->Asl.Parent = Op; + RootOp->Asl.Parent = Op; (void) OpcSetOptimalIntegerSize (RootOp); @@ -532,10 +540,10 @@ OpcAmlConstantWalk ( /* Peer to the child is the raw buffer data */ RootOp = TrAllocateNode (PARSEOP_RAW_DATA); - RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; - RootOp->Asl.AmlLength = ObjDesc->Buffer.Length; - RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer; - RootOp->Asl.Parent = Op->Asl.Parent; + RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; + RootOp->Asl.AmlLength = ObjDesc->Buffer.Length; + RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer; + RootOp->Asl.Parent = Op->Asl.Parent; Op->Asl.Next = RootOp; Op = RootOp; @@ -548,7 +556,7 @@ OpcAmlConstantWalk ( default: printf ("Unsupported return type: %s\n", - AcpiUtGetObjectTypeName (ObjDesc)); + AcpiUtGetObjectTypeName (ObjDesc)); break; } } @@ -557,7 +565,62 @@ OpcAmlConstantWalk ( Op->Asl.Child = NULL; AcpiDsDeleteWalkState (WalkState); - return (AE_CTRL_DEPTH); } + +/******************************************************************************* + * + * FUNCTION: OpcUpdateIntegerNode + * + * PARAMETERS: Op - Current parse object + * + * RETURN: None + * + * DESCRIPTION: Update node to the correct integer type. + * + ******************************************************************************/ + +static void +OpcUpdateIntegerNode ( + ACPI_PARSE_OBJECT *Op, + UINT64 Value) +{ + + Op->Common.Value.Integer = Value; + + /* + * The AmlLength is used by the parser to indicate a constant, + * (if non-zero). Length is either (1/2/4/8) + */ + switch (Op->Asl.AmlLength) + { + case 1: + TrUpdateNode (PARSEOP_BYTECONST, Op); + Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE; + break; + + case 2: + TrUpdateNode (PARSEOP_WORDCONST, Op); + Op->Asl.AmlOpcode = AML_RAW_DATA_WORD; + break; + + case 4: + TrUpdateNode (PARSEOP_DWORDCONST, Op); + Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD; + break; + + case 8: + TrUpdateNode (PARSEOP_QWORDCONST, Op); + Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD; + break; + + case 0: + default: + OpcSetOptimalIntegerSize (Op); + TrUpdateNode (PARSEOP_INTEGER, Op); + break; + } + + Op->Asl.AmlLength = 0; +} diff --git a/source/compiler/aslmessages.h b/source/compiler/aslmessages.h index 56951bc09..a1d6d1c28 100644 --- a/source/compiler/aslmessages.h +++ b/source/compiler/aslmessages.h @@ -269,6 +269,7 @@ typedef enum ASL_MSG_UPPER_CASE, ASL_MSG_VENDOR_LIST, ASL_MSG_WRITE, + ASL_MSG_RANGE, /* These messages are used by the Preprocessor only */ @@ -443,6 +444,7 @@ char *AslMessages [] = { /* ASL_MSG_UPPER_CASE */ "Non-hex letters must be upper case", /* ASL_MSG_VENDOR_LIST */ "Too many vendor data bytes (7 max)", /* ASL_MSG_WRITE */ "Could not write file", +/* ASL_MSG_RANGE */ "Constant out of range", /* Preprocessor */ diff --git a/source/compiler/asltree.c b/source/compiler/asltree.c index f7a5fd792..ebf87f3bf 100644 --- a/source/compiler/asltree.c +++ b/source/compiler/asltree.c @@ -140,9 +140,9 @@ TrGetNodeFlagName ( * * PARAMETERS: None * - * RETURN: New parse node. Aborts on allocation failure + * RETURN: New parse node. Aborts on allocation failure * - * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local + * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local * dynamic memory manager for performance reasons (This has a * major impact on the speed of the compiler.) * @@ -170,7 +170,7 @@ TrGetNextNode ( * * PARAMETERS: ParseOpcode - Opcode to be assigned to the node * - * RETURN: New parse node. Aborts on allocation failure + * RETURN: New parse node. Aborts on allocation failure * * DESCRIPTION: Allocate and initialize a new parse node for the parse tree * @@ -205,7 +205,7 @@ TrAllocateNode ( * * RETURN: None * - * DESCRIPTION: "release" a node. In truth, nothing is done since the node + * DESCRIPTION: "release" a node. In truth, nothing is done since the node * is part of a larger buffer * ******************************************************************************/ @@ -228,9 +228,9 @@ TrReleaseNode ( * * RETURN: The updated node * - * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to + * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to * change an opcode to DEFAULT_ARG so that the node is ignored - * during the code generation. Also used to set generic integers + * during the code generation. Also used to set generic integers * to a specific size (8, 16, 32, or 64 bits) * ******************************************************************************/ @@ -258,19 +258,21 @@ TrUpdateNode ( switch (ParseOpcode) { case PARSEOP_BYTECONST: - Op->Asl.Value.Integer = 0xFF; + Op->Asl.Value.Integer = ACPI_UINT8_MAX; break; case PARSEOP_WORDCONST: - Op->Asl.Value.Integer = 0xFFFF; + Op->Asl.Value.Integer = ACPI_UINT16_MAX; break; case PARSEOP_DWORDCONST: - Op->Asl.Value.Integer = 0xFFFFFFFF; + Op->Asl.Value.Integer = ACPI_UINT32_MAX; break; + /* Don't need to do the QWORD case */ + default: - /* Don't care about others, don't need to check QWORD */ + /* Don't care about others */ break; } } @@ -285,15 +287,18 @@ TrUpdateNode ( switch (ParseOpcode) { case PARSEOP_BYTECONST: - Op = UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX); + UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX); + Op->Asl.Value.Integer &= ACPI_UINT8_MAX; break; case PARSEOP_WORDCONST: - Op = UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX); + UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX); + Op->Asl.Value.Integer &= ACPI_UINT16_MAX; break; case PARSEOP_DWORDCONST: - Op = UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX); + UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX); + Op->Asl.Value.Integer &= ACPI_UINT32_MAX; break; default: @@ -387,7 +392,7 @@ TrGetNodeFlagName ( * * RETURN: The updated parser op * - * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set + * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set * ******************************************************************************/ @@ -407,8 +412,41 @@ TrSetNodeFlags ( } Op->Asl.CompileFlags |= Flags; + return (Op); +} - return Op; + +/******************************************************************************* + * + * FUNCTION: TrSetNodeAmlLength + * + * PARAMETERS: Op - An existing parse node + * Length - AML Length + * + * RETURN: The updated parser op + * + * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate + * the presence of a node that must be reduced to a fixed length + * constant. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +TrSetNodeAmlLength ( + ACPI_PARSE_OBJECT *Op, + UINT32 Length) +{ + + DbgPrint (ASL_PARSE_OUTPUT, + "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length); + + if (!Op) + { + return NULL; + } + + Op->Asl.AmlLength = Length; + return (Op); } @@ -448,7 +486,7 @@ TrSetEndLineNumber ( * * PARAMETERS: ParseOpcode - New opcode to be assigned to the node * - * RETURN: Pointer to the new node. Aborts on allocation failure + * RETURN: Pointer to the new node. Aborts on allocation failure * * DESCRIPTION: Create a simple leaf node (no children or peers, and no value * assigned to the node) @@ -478,7 +516,7 @@ TrCreateLeafNode ( * * PARAMETERS: ParseOpcode - The constant opcode * - * RETURN: Pointer to the new node. Aborts on allocation failure + * RETURN: Pointer to the new node. Aborts on allocation failure * * DESCRIPTION: Create a leaf node (no children or peers) for one of the * special constants - __LINE__, __FILE__, and __DATE__. @@ -560,7 +598,7 @@ TrCreateConstantLeafNode ( * PARAMETERS: ParseOpcode - New opcode to be assigned to the node * Value - Value to be assigned to the node * - * RETURN: Pointer to the new node. Aborts on allocation failure + * RETURN: Pointer to the new node. Aborts on allocation failure * * DESCRIPTION: Create a leaf node (no children or peers) with a value * assigned to it @@ -625,9 +663,9 @@ TrCreateValuedLeafNode ( * PARAMETERS: ParseOpcode - Opcode to be assigned to the node * NumChildren - Number of children to follow * ... - A list of child nodes to link to the new - * node. NumChildren long. + * node. NumChildren long. * - * RETURN: Pointer to the new node. Aborts on allocation failure + * RETURN: Pointer to the new node. Aborts on allocation failure * * DESCRIPTION: Create a new parse node and link together a list of child * nodes underneath the new node. @@ -693,7 +731,7 @@ TrCreateNode ( /* * If child is NULL, this means that an optional argument - * was omitted. We must create a placeholder with a special + * was omitted. We must create a placeholder with a special * opcode (DEFAULT_ARG) so that the code generator will know * that it must emit the correct default for this argument */ @@ -747,7 +785,7 @@ TrCreateNode ( * PARAMETERS: Op - An existing parse node * NumChildren - Number of children to follow * ... - A list of child nodes to link to the new - * node. NumChildren long. + * node. NumChildren long. * * RETURN: The updated (linked) node * @@ -817,7 +855,7 @@ TrLinkChildren ( /* * If child is NULL, this means that an optional argument - * was omitted. We must create a placeholder with a special + * was omitted. We must create a placeholder with a special * opcode (DEFAULT_ARG) so that the code generator will know * that it must emit the correct default for this argument */ @@ -872,7 +910,7 @@ TrLinkChildren ( * * RETURN: Op1 or the non-null node. * - * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null. + * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null. * ******************************************************************************/ diff --git a/source/compiler/aslutils.c b/source/compiler/aslutils.c index de7ea0dfe..b3def49bb 100644 --- a/source/compiler/aslutils.c +++ b/source/compiler/aslutils.c @@ -663,36 +663,23 @@ UtCheckIntegerRange ( UINT32 LowValue, UINT32 HighValue) { - char *ParseError = NULL; - char Buffer[64]; - if (!Op) { return NULL; } - if (Op->Asl.Value.Integer < LowValue) + if ((Op->Asl.Value.Integer < LowValue) || + (Op->Asl.Value.Integer > HighValue)) { - ParseError = "Value below valid range"; - Op->Asl.Value.Integer = LowValue; + sprintf (MsgBuffer, "0x%X, allowable: 0x%X-0x%X", + (UINT32) Op->Asl.Value.Integer, LowValue, HighValue); + + AslError (ASL_ERROR, ASL_MSG_RANGE, Op, MsgBuffer); + return (NULL); } - if (Op->Asl.Value.Integer > HighValue) - { - ParseError = "Value above valid range"; - Op->Asl.Value.Integer = HighValue; - } - - if (ParseError) - { - sprintf (Buffer, "%s 0x%X-0x%X", ParseError, LowValue, HighValue); - AslCompilererror (Buffer); - - return NULL; - } - - return Op; + return (Op); }