/// <summary> /// Recursive workhorse method for the method <see cref="GetAggregateFields"/>. /// </summary> /// /// <param name="aggregateType">Type of the aggregate that is being accessed.</param> /// <param name="offset">Offset of the access from the start of the aggregate, /// in bits.</param> /// <param name="accessType">Type of the aggregate access.</param> /// <param name="accessBitSize">Bit-size of the aggregate access.</param> /// <param name="getArrayElements">True if, and only if, the elements of /// a fixed-size array should be treated as separate fields of the aggregate.</param> /// <param name="accessSoFar">Expression that represents the access so far.</param> /// <param name="path">Path that contains the aggregate.</param> /// <returns>List of AggregateField objects, each of which represents /// the aggregate fields that the input aggregate access overlaps.</returns> private static List <AggregateField> GetAggregateFieldsHelper(AggregateType aggregateType, int offset, Phx.Types.Type accessType, int accessBitSize, bool getArrayElements, Expression accessSoFar, Path path) { Utilities.Configuration config = path.Config; List <AggregateField> result = new List <AggregateField>(); int completedOffset = 0; FieldSymbol currentFieldSymbol = aggregateType.FieldSymbolList; while (currentFieldSymbol != null) { /* Obtain the necessary information from the current field symbol. */ string fieldName = currentFieldSymbol.ToString(); int fieldStartOffset = currentFieldSymbol.BitOffset; Phx.Types.Type fieldType = currentFieldSymbol.Type; int fieldEndOffset = (fieldStartOffset + (int)fieldType.BitSize) - 1; /* Move to the next field symbol for the subsequent iteration. */ currentFieldSymbol = currentFieldSymbol.NextFieldSymbol; if (fieldStartOffset < completedOffset) { /* Skip this field if it starts at an offset in the part of * the aggregate that has already been examined. */ continue; } else { /* Move the completed offset pointer to the end of the field currently * being examined. This indicates that, after this iteration * is complete, the part of the aggregate prior to the pointer * has already been examined. */ completedOffset = fieldEndOffset; } if (((offset <= fieldStartOffset) && (fieldStartOffset <= (offset + accessBitSize) - 1)) || ((offset > fieldStartOffset) && (offset <= fieldEndOffset))) { /* Attach a unique identifier to each field name. */ string newFieldName = String.Format("{0}{1}{2}{3}", config.IDENT_FIELD, fieldName, config.IDENT_AGGREGATE, GetAggregateName(aggregateType)); /* Make an array variable Expression for the field, since we represent * aggregate accesses as accesses into an array. */ Expression newArrayVar = new Expression(OperatorStore.ArrayVariableOp, newFieldName); newArrayVar.Type = Phx.Types.PointerType.New(aggregateType.TypeTable, Phx.Types.PointerTypeKind.UnmanagedPointer, path.Config.WORD_BITSIZE, fieldType, fieldType.TypeSymbol); path.AddVariable(newArrayVar); /* Convert the array variable Expression into the equivalent * pointer Expression, represented as a dereferencing function. */ newArrayVar = ExpressionHelper.MakeDereferencingFunction(newArrayVar, path); /* Apply the dereferencing function on the Expression generated so far. */ List <Expression> argExprs = new List <Expression>(); argExprs.Add(accessSoFar); argExprs.Add(new Constant(0, config.WORD_BITSIZE)); Expression fieldAccessExpr = ExpressionHelper.ApplyFunction(newArrayVar, argExprs, path); fieldAccessExpr = ExpressionHelper.LookupAndReplaceOffset(fieldAccessExpr, fieldType, false, path); if (fieldType.IsAggregateType) { /* Recurse into the field, if the field is itself an aggregate. */ AggregateType innerAggregateType = fieldType.AsAggregateType; List <AggregateField> innerAggregateFields = GetAggregateFieldsHelper(innerAggregateType, Math.Max((offset - fieldStartOffset), 0), accessType, (accessBitSize - Math.Max(fieldStartOffset - offset, 0)), getArrayElements, fieldAccessExpr, path); foreach (AggregateField innerAggregateField in innerAggregateFields) { /* Include the offset of the field inside * the enclosing aggregate type. */ innerAggregateField.StartOffset += fieldStartOffset; result.Add(innerAggregateField); } } else if (fieldType.IsUnmanagedArrayType && !ExpressionHelper.AreSameTypes(fieldType, accessType) && getArrayElements) { List <Pair <Expression, int> > arrayElements = ExpressionHelper.GetArrayElementsInRange(fieldAccessExpr, Math.Max((offset - fieldStartOffset), 0), (accessBitSize - Math.Max(fieldStartOffset - offset, 0)), path); foreach (Pair <Expression, int> arrayElementAndOffset in arrayElements) { Expression arrayElementExpr = arrayElementAndOffset.First; int arrayElementOffset = arrayElementAndOffset.Second; result.Add(new AggregateField(aggregateType, arrayElementExpr, (fieldStartOffset + arrayElementOffset), arrayElementExpr.BitSize)); } } else { result.Add(new AggregateField(aggregateType, fieldAccessExpr, fieldStartOffset, fieldType.BitSize)); } } } Trace.Assert(result.Count > 0, "PHOENIX: Field(s) not found."); return(result); }