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);
/*******************************************************************************
*
@ -393,8 +398,8 @@ OpcAmlConstantWalk (
WalkState->NextOp = NULL;
WalkState->Params = NULL;
WalkState->CallerReturnDesc = &ObjDesc;
WalkState->WalkType = WalkType;
WalkState->CallerReturnDesc = &ObjDesc;
/*
* Examine the entire subtree -- all nodes must be constants
@ -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 */
Op->Asl.ParseOpcode = PARSEOP_INTEGER;
Op->Common.Value.Integer = 0;
OpcSetOptimalIntegerSize (Op);
OpcUpdateIntegerNode (Op, 0);
}
else
{
@ -484,13 +493,12 @@ 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;
@ -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

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

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