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.
This commit is contained in:
Robert Moore 2012-08-03 14:24:58 -07:00
parent c5667d3f74
commit ffefc5e308
6 changed files with 189 additions and 86 deletions

View File

@ -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,

View File

@ -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 {}
;

View File

@ -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;
}

View File

@ -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 */

View File

@ -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.
*
******************************************************************************/

View File

@ -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);
}