GP-4031 x86 System V ABI

This commit is contained in:
caheckman 2024-02-20 19:13:53 +00:00
parent 362f571b19
commit c674e1f2ec
20 changed files with 1668 additions and 185 deletions

View file

@ -29,24 +29,150 @@ ElementId ELEM_POSITION = ElementId("position",280);
ElementId ELEM_VARARGS = ElementId("varargs",281);
ElementId ELEM_HIDDEN_RETURN = ElementId("hidden_return",282);
ElementId ELEM_JOIN_PER_PRIMITIVE = ElementId("join_per_primitive",283);
ElementId ELEM_JOIN_DUAL_CLASS = ElementId("join_dual_class",285);
/// \brief Extract an ordered list of primitive data-types making up the given data-type
/// \brief Check that a big Primitive properly overlaps smaller Primitives
///
/// The primitive data-types are passed back in an array. If the given data-type is already
/// primitive, it is passed back as is. Otherwise if it is composite, its components are
/// recursively listed. If a maximum number of extracted primitives is exceeded, or if the
/// primitives are not properly aligned, or if a non-primitive non-composite data-type is
/// encountered, false is returned.
/// If the big Primitive does not properly overlap the smaller Primitives starting at the given \b point,
/// return -1. Otherwise, if the big Primitive is floating-point, add the overlapped primitives to the
/// common refinement list, or if not a floating-point, add the big Primitive to the list.
/// (Integer primitives are \e preferred over floating-point primitives in this way) Return the index of
/// the next primitive after the overlap.
/// \param res holds the common refinement list
/// \param small is the list of Primitives that are overlapped
/// \param point is the index of the first overlap
/// \param big is the big overlapping Primitive
/// \return the index of the next Primitive after the overlap or -1 if the overlap is invalid
int4 PrimitiveExtractor::checkOverlap(vector<Primitive> &res,vector<Primitive> &small,int4 point,Primitive &big)
{
int4 endOff = big.offset + big.dt->getAlignSize();
// If big data-type is a float, let smaller primitives override it, otherwise we keep the big primitive
bool useSmall = big.dt->getMetatype() == TYPE_FLOAT;
while(point < small.size()) {
int4 curOff = small[point].offset;
if (curOff >= endOff) break;
curOff += small[point].dt->getAlignSize();
if (curOff > endOff)
return -1; // Improper overlap of the end of big
if (useSmall)
res.push_back(small[point]);
point += 1;
}
if (!useSmall) // If big data-type was preferred
res.push_back(big); // use big Primitive in the refinement
return point;
}
/// \brief Overwrite \b first list with common refinement of \b first and \b second
///
/// Given two sets of overlapping Primitives, find a \e common \e refinement of the lists.
/// If there is any partial overlap of two Primitives, \b false is returned.
/// If the same primitive data-type occurs at the same offset, it is included in the refinement.
/// Otherwise an integer data-type is preferred over a floating-point data-type, or a bigger
/// primitive is preferred over smaller overlapping primitives.
/// The final refinement replaces the \b first list.
/// \param first is the first list of Primitives
/// \param second is the second list
/// \return \b true if a refinement was successfully constructed
bool PrimitiveExtractor::commonRefinement(vector<Primitive> &first,vector<Primitive> &second)
{
int4 firstPoint = 0;
int4 secondPoint = 0;
vector<Primitive> common;
while(firstPoint < first.size() && secondPoint < second.size()) {
Primitive &firstElement( first[firstPoint] );
Primitive &secondElement( second[secondPoint] );
if (firstElement.offset < secondElement.offset &&
firstElement.offset + firstElement.dt->getAlignSize() <= secondElement.offset) {
common.push_back(firstElement);
firstPoint += 1;
continue;
}
if (secondElement.offset < firstElement.offset &&
secondElement.offset + secondElement.dt->getAlignSize() <= firstElement.offset) {
common.push_back(secondElement);
secondPoint += 1;
continue;
}
if (firstElement.dt->getAlignSize() >= secondElement.dt->getAlignSize()) {
secondPoint = checkOverlap(common,second,secondPoint,firstElement);
if (secondPoint < 0) return false;
firstPoint += 1;
}
else {
firstPoint = checkOverlap(common,first,firstPoint,secondElement);
if (firstPoint < 0) return false;
secondPoint += 1;
}
}
// Add any tail primitives from either list
while(firstPoint < first.size()) {
common.push_back(first[firstPoint]);
firstPoint += 1;
}
while(secondPoint < second.size()) {
common.push_back(second[secondPoint]);
secondPoint += 1;
}
first.swap(common); // Replace first with the refinement
return true;
}
/// Form a primitive list for each field of the union. Then, if possible, form a common refinement
/// of all the primitive lists and add to the end of \b this extractor's list.
/// \param dt is the union data-type
/// \param max is the maximum number primitives allowed for \b this extraction
/// \param offset is the starting offset of the union within the parent
/// \return \b true if a common refinement was found and appended
bool PrimitiveExtractor::handleUnion(TypeUnion *dt,int4 max,int4 offset)
{
if ((flags & union_invalid) != 0)
return false;
int4 num = dt->numDepend();
if (num == 0)
return false;
const TypeField *curField = dt->getField(0);
PrimitiveExtractor common(curField->type,false,offset + curField->offset,max);
if (!common.isValid())
return false;
for(int4 i=1;i<num;++i) {
curField = dt->getField(i);
PrimitiveExtractor next(curField->type,false,offset + curField->offset,max);
if (!next.isValid())
return false;
if (!commonRefinement(common.primitives,next.primitives))
return false;
}
if (primitives.size() + common.primitives.size() > max)
return false;
for(int4 i=0;i<common.primitives.size();++i)
primitives.push_back(common.primitives[i]);
return true;
}
/// An array of the primitive data-types, with their associated offsets, is constructed.
/// If the given data-type is already primitive it is put in the array by itself. Otherwise
/// if it is composite, its components are recursively added to the array.
/// Boolean properties about the primitives encountered are recorded:
/// - Are any of the primitives \b undefined
/// - Are all the primitives properly aligned.
///
/// If a maximum number of extracted primitives is exceeded, or if an illegal
/// data-type is encountered (\b void or other internal data-type) false is returned.
/// \param dt is the given data-type to extract primitives from
/// \param max is the maximum number of primitives to extract before giving up
/// \param res will hold the list of primitives
/// \param offset is the starting offset to associate with the first primitive
/// \return \b true if all primitives were extracted
bool DatatypeFilter::extractPrimitives(Datatype *dt,int4 max,vector<Datatype *> &res)
bool PrimitiveExtractor::extract(Datatype *dt,int4 max,int4 offset)
{
switch(dt->getMetatype()) {
case TYPE_UNKNOWN:
return false; // Do not consider undefined data-types as primitive
flags |= unknown_element; ///< Mark that the data-type contains an unknown primitive
// fallthru
case TYPE_INT:
case TYPE_UINT:
case TYPE_BOOL:
@ -54,46 +180,63 @@ bool DatatypeFilter::extractPrimitives(Datatype *dt,int4 max,vector<Datatype *>
case TYPE_FLOAT:
case TYPE_PTR:
case TYPE_PTRREL:
if (res.size() >= max)
if (primitives.size() >= max)
return false;
res.push_back(dt);
primitives.emplace_back(dt,offset);
return true;
case TYPE_ARRAY:
{
int4 numEls = ((TypeArray *)dt)->numElements();
Datatype *base = ((TypeArray *)dt)->getBase();
for(int4 i=0;i<numEls;++i) {
if (!extractPrimitives(base,max,res))
if (!extract(base,max,offset))
return false;
offset += base->getAlignSize();
}
return true;
}
case TYPE_UNION:
return handleUnion((TypeUnion *)dt,max,offset);
case TYPE_STRUCT:
break;
default:
return false;
}
TypeStruct *structPtr = (TypeStruct *)dt;
int4 curOff = 0;
vector<TypeField>::const_iterator enditer = structPtr->endField();
int4 expectedOff = offset;
for(vector<TypeField>::const_iterator iter=structPtr->beginField();iter!=enditer;++iter) {
Datatype *compDt = (*iter).type;
int4 nextOff = (*iter).offset;
int4 align = dt->getAlignment();
int4 rem = curOff % align;
int4 curOff = (*iter).offset + offset;
int4 align = compDt->getAlignment();
if (curOff % align != 0)
flags |= unaligned;
int4 rem = expectedOff % align;
if (rem != 0) {
curOff += (align - rem);
expectedOff += (align - rem);
}
if (curOff != nextOff) {
return false;
if (expectedOff != curOff) {
flags |= extra_space;
}
curOff = nextOff + compDt->getAlignSize();
if (!extractPrimitives(compDt,max,res))
if (!extract(compDt,max,curOff))
return false;
}
expectedOff = curOff + compDt->getAlignSize();
}
return true;
}
/// \param dt is data-type extract from
/// \param unionIllegal is \b true if unions encountered during extraction are considered illegal
/// \param offset is the starting offset to associate with the data-type
/// \param max is the maximum number of primitives to extract before giving up
PrimitiveExtractor::PrimitiveExtractor(Datatype *dt,bool unionIllegal,int offset,int4 max)
{
flags = unionIllegal ? union_invalid : 0;
if (!extract(dt,max,offset))
flags |= invalid;
}
/// \param decoder is the given stream decoder
/// \return the new data-type filter instance
DatatypeFilter *DatatypeFilter::decodeFilter(Decoder &decoder)
@ -196,14 +339,15 @@ bool HomogeneousAggregate::filter(Datatype *dt) const
type_metatype meta = dt->getMetatype();
if (meta != TYPE_ARRAY && meta != TYPE_STRUCT)
return false;
vector<Datatype *> res;
if (!extractPrimitives(dt, 4, res) || res.empty())
PrimitiveExtractor primitives(dt,true,0,4);
if (!primitives.isValid() || primitives.size() == 0 || primitives.containsUnknown()
|| !primitives.isAligned() || primitives.containsHoles())
return false;
Datatype *base = res[0];
Datatype *base = primitives.get(0).dt;
if (base->getMetatype() != metaType)
return false;
for(int4 i=1;i<res.size();++i) {
if (res[i] != base)
for(int4 i=1;i<primitives.size();++i) {
if (primitives.get(i).dt != base)
return false;
}
return true;
@ -332,6 +476,12 @@ void DatatypeMatchFilter::decode(Decoder &decoder)
decoder.closeElement(elemId);
}
bool AssignAction::fillinOutputMap(ParamActive *active) const
{
return false; // Default implementation for an inactive action
}
/// \brief Read the next model rule action element from the stream
///
/// Allocate the action object corresponding to the element and configure it.
@ -366,6 +516,9 @@ AssignAction *AssignAction::decodeAction(Decoder &decoder,const ParamListStandar
}
action = new MultiMemberAssign(TYPECLASS_GENERAL,false,consumeMostSig,res);
}
else if (elemId == ELEM_JOIN_DUAL_CLASS) {
action = new MultiSlotDualAssign(res);
}
else
throw DecoderError("Expecting model rule action");
action->decode(decoder);
@ -397,15 +550,7 @@ AssignAction *AssignAction::decodeSideeffect(Decoder &decoder,const ParamListSta
void GotoStack::initializeEntry(void)
{
const list<ParamEntry> &entries(resource->getEntry());
list<ParamEntry>::const_iterator iter;
for(iter=entries.begin();iter!=entries.end();++iter) {
const ParamEntry &entry( *iter );
if (!entry.isExclusion() && entry.getSpace()->getType() == IPTR_SPACEBASE) {
stackEntry = &entry;
break;
}
}
stackEntry = resource->getStackEntry();
if (stackEntry == (const ParamEntry *)0)
throw LowlevelError("Cannot find matching <pentry> for action: gotostack");
}
@ -416,12 +561,14 @@ GotoStack::GotoStack(const ParamListStandard *res,int4 val)
: AssignAction(res)
{
stackEntry = (const ParamEntry *)0;
fillinOutputActive = true;
}
GotoStack::GotoStack(const ParamListStandard *res)
: AssignAction(res)
{
stackEntry = (const ParamEntry *)0;
fillinOutputActive = true;
initializeEntry();
}
@ -435,6 +582,23 @@ uint4 GotoStack::assignAddress(Datatype *dt,const PrototypePieces &proto,int4 po
return success;
}
bool GotoStack::fillinOutputMap(ParamActive *active) const
{
int4 count = 0;
for(int4 i=0;i<active->getNumTrials();++i) {
ParamTrial &trial(active->getTrial(i));
const ParamEntry *entry = trial.getEntry();
if (entry == (const ParamEntry *)0) break;
if (entry != stackEntry)
return false;
count += 1;
if (count > 1)
return false;
}
return (count == 1);
}
void GotoStack::decode(Decoder &decoder)
{
@ -477,20 +641,9 @@ void ConvertToPointer::decode(Decoder &decoder)
void MultiSlotAssign::initializeEntries(void)
{
const list<ParamEntry> &entries(resource->getEntry());
firstIter = entries.end();
list<ParamEntry>::const_iterator iter;
for(iter=entries.begin();iter!=entries.end();++iter) {
const ParamEntry &entry( *iter );
if (firstIter == entries.end() && entry.isExclusion() && entry.getType() == resourceType &&
entry.getAllGroups().size() == 1)
firstIter = iter; // First matching resource size
if (!entry.isExclusion() && entry.getSpace()->getType() == IPTR_SPACEBASE) {
stackEntry = &entry;
break;
}
}
if (firstIter == entries.end())
firstIter = resource->getFirstIter(resourceType);
stackEntry = resource->getStackEntry();
if (firstIter == resource->getEntry().end())
throw LowlevelError("Could not find matching resources for action: join");
if (consumeFromStack && stackEntry == (const ParamEntry *)0)
throw LowlevelError("Cannot find matching <pentry> for action: join");
@ -502,6 +655,7 @@ MultiSlotAssign::MultiSlotAssign(const ParamListStandard *res)
: AssignAction(res)
{
resourceType = TYPECLASS_GENERAL; // Join general purpose registers
fillinOutputActive = true;
uint4 listType = res->getType();
// Consume from stack on input parameters by default
consumeFromStack = (listType != ParamList::p_register_out && listType != ParamList::p_standard_out);
@ -520,6 +674,7 @@ MultiSlotAssign::MultiSlotAssign(type_class store,bool stack,bool mostSig,bool a
: AssignAction(res)
{
resourceType = store;
fillinOutputActive = true;
consumeFromStack = stack;
consumeMostSig = mostSig;
enforceAlignment = align;
@ -620,6 +775,55 @@ uint4 MultiSlotAssign::assignAddress(Datatype *dt,const PrototypePieces &proto,i
return success;
}
bool MultiSlotAssign::fillinOutputMap(ParamActive *active) const
{
int4 count = 0;
int4 curGroup = -1;
int4 partial = -1;
for(int4 i=0;i<active->getNumTrials();++i) {
ParamTrial &trial(active->getTrial(i));
const ParamEntry *entry = trial.getEntry();
if (entry == (const ParamEntry *)0) break;
if (entry->getType() != resourceType) // Trials must come from action's type_class
return false;
if (count == 0) {
if (!entry->isFirstInClass())
return false; // Trials must start on first entry of the type_class
}
else {
if (entry->getGroup() != curGroup + 1) // Trials must be consecutive
return false;
}
curGroup = entry->getGroup();
if (trial.getSize() != entry->getSize()) {
if (partial != -1)
return false; // At most, one trial can be partial size
partial = i;
}
count += 1;
}
if (partial != -1) {
if (justifyRight) {
if (partial != 0) return false;
}
else {
if (partial != count - 1) return false;
}
ParamTrial &trial(active->getTrial(partial));
if (justifyRight == consumeMostSig) {
if (trial.getOffset() != 0)
return false; // Partial entry must be least sig bytes
}
else {
if (trial.getOffset() + trial.getSize() != trial.getEntry()->getSize()) {
return false; // Partial entry must be most sig bytes
}
}
}
return (count > 0);
}
void MultiSlotAssign::decode(Decoder &decoder)
{
@ -648,6 +852,7 @@ MultiMemberAssign::MultiMemberAssign(type_class store,bool stack,bool mostSig,co
resourceType = store;
consumeFromStack = stack;
consumeMostSig = mostSig;
fillinOutputActive = true;
}
uint4 MultiMemberAssign::assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
@ -655,12 +860,13 @@ uint4 MultiMemberAssign::assignAddress(Datatype *dt,const PrototypePieces &proto
{
vector<int4> tmpStatus = status;
vector<VarnodeData> pieces;
vector<Datatype *> primitives;
if (!DatatypeFilter::extractPrimitives(dt,16,primitives) || primitives.empty())
PrimitiveExtractor primitives(dt,false,0,16);
if (!primitives.isValid() || primitives.size() == 0 || primitives.containsUnknown()
|| !primitives.isAligned() || primitives.containsHoles())
return fail;
ParameterPieces param;
for(int4 i=0;i<primitives.size();++i) {
Datatype *curType = primitives[i];
Datatype *curType = primitives.get(i).dt;
if (resource->assignAddressFallback(resourceType, curType, !consumeFromStack, tmpStatus,param) == fail)
return fail;
pieces.push_back(VarnodeData());
@ -687,6 +893,33 @@ uint4 MultiMemberAssign::assignAddress(Datatype *dt,const PrototypePieces &proto
return success;
}
bool MultiMemberAssign::fillinOutputMap(ParamActive *active) const
{
int4 count = 0;
int4 curGroup = -1;
for(int4 i=0;i<active->getNumTrials();++i) {
ParamTrial &trial(active->getTrial(i));
const ParamEntry *entry = trial.getEntry();
if (entry == (const ParamEntry *)0) break;
if (entry->getType() != resourceType) // Trials must come from action's type_class
return false;
if (count == 0) {
if (!entry->isFirstInClass())
return false;
}
else {
if (entry->getGroup() != curGroup + 1) // Trials must be consecutive
return false;
}
curGroup = entry->getGroup();
if (trial.getOffset() != 0)
return false; // Entry must be justified
count += 1;
}
return (count > 0);
}
void MultiMemberAssign::decode(Decoder &decoder)
{
@ -701,10 +934,252 @@ void MultiMemberAssign::decode(Decoder &decoder)
decoder.closeElement(elemId);
}
/// Find the first ParamEntry matching the \b baseType, and the first matching \b altType.
void MultiSlotDualAssign::initializeEntries(void)
{
baseIter = resource->getFirstIter(baseType);
altIter = resource->getFirstIter(altType);
list<ParamEntry>::const_iterator enditer = resource->getEntry().end();
if (baseIter == enditer || altIter == enditer)
throw LowlevelError("Could not find matching resources for action: join_dual_class");
tileSize = (*baseIter).getSize();
if (tileSize != (*altIter).getSize())
throw LowlevelError("Storage class register sizes do not match for action: join_dual_class");
}
/// \brief Get the first unused ParamEntry that matches the given storage class
///
/// \param iter points to the starting entry to search
/// \param storage is the given storage class to match
/// \param status is the usage information for the entries
/// \return the iterator to the unused ParamEntry
list<ParamEntry>::const_iterator MultiSlotDualAssign::getFirstUnused(list<ParamEntry>::const_iterator iter,
type_class storage,vector<int4> &status) const
{
list<ParamEntry>::const_iterator endIter = resource->getEntry().end();
for(;iter != endIter; ++iter) {
const ParamEntry &entry( *iter );
if (!entry.isExclusion())
break; // Reached end of resource list
if (entry.getType() != storage || entry.getAllGroups().size() != 1)
continue; // Not a single register from desired resource
if (status[entry.getGroup()] != 0)
continue; // Already consumed
return iter;
}
return endIter;
}
/// \brief Get the storage class to use for the specific section of the data-type
///
/// For the section starting at \b off extending through \b tileSize bytes, if any primitive overlaps
/// the boundary of the section, return -1. Otherwise, if all the primitive data-types in the section
/// match the alternate storage class, return 1, or if one or more does not match, return 0.
/// The \b index of the first primitive after the start of the section is provided and is then updated
/// to be the first primitive after the end of the section.
/// \param primitives is the list of primitive data-types making up the data-type
/// \param off is the starting offset of the section
/// \param index is the index of the first primitive in the section
/// \return 0 for a base tile, 1 for an alternate tile, -1 for boundary overlaps
int4 MultiSlotDualAssign::getTileClass(const PrimitiveExtractor &primitives,int4 off,int4 &index) const
{
int4 res = 1;
int4 count = 0;
int4 endBoundary = off + tileSize;
while(index < primitives.size()) {
const PrimitiveExtractor::Primitive &element( primitives.get(index) );
if (element.offset < off) return -1;
if (element.offset >= endBoundary) break;
if (element.offset + element.dt->getSize() > endBoundary) return -1;
count += 1;
index += 1;
type_class storage = metatype2typeclass(element.dt->getMetatype());
if (storage != altType)
res = 0;
}
if (count == 0) return -1; // Must be at least one primitive in section
return res;
}
/// Set default configuration
/// \param res is the new resource set to associate with \b this action
MultiSlotDualAssign::MultiSlotDualAssign(const ParamListStandard *res)
: AssignAction(res)
{
fillinOutputActive = true;
baseType = TYPECLASS_GENERAL; // Tile from general purpose registers
altType = TYPECLASS_FLOAT; // Use specialized registers for floating-point components
consumeMostSig = false;
justifyRight = false;
AddrSpace *spc = res->getSpacebase();
if (spc != (AddrSpace *)0 && spc->isBigEndian()) {
consumeMostSig = true;
justifyRight = true;
}
tileSize = 0;
}
MultiSlotDualAssign::MultiSlotDualAssign(type_class baseStore,type_class altStore,bool mostSig,bool justRight,
const ParamListStandard *res)
: AssignAction(res)
{
fillinOutputActive = true;
baseType = baseStore;
altType = altStore;
consumeMostSig = mostSig;
justifyRight = justRight;
initializeEntries();
}
uint4 MultiSlotDualAssign::assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
vector<int4> &status,ParameterPieces &res) const
{
PrimitiveExtractor primitives(dt,false,0,1024);
if (!primitives.isValid() || primitives.size() == 0 || primitives.containsHoles())
return fail;
int4 primitiveIndex = 0;
vector<int4> tmpStatus = status;
vector<VarnodeData> pieces;
int4 typeSize = dt->getSize();
int4 sizeLeft = typeSize;
list<ParamEntry>::const_iterator iterBase = baseIter;
list<ParamEntry>::const_iterator iterAlt = altIter;
list<ParamEntry>::const_iterator endIter = resource->getEntry().end();
while(sizeLeft > 0) {
list<ParamEntry>::const_iterator iter;
int4 iterType = getTileClass(primitives, typeSize-sizeLeft, primitiveIndex);
if (iterType < 0)
return fail;
if (iterType == 0) {
iter = iterBase = getFirstUnused(iterBase, baseType, tmpStatus);
}
else {
iter = iterAlt = getFirstUnused(iterAlt, altType, tmpStatus);
}
if (iter == endIter)
return fail; // Out of the particular resource
const ParamEntry &entry( *iter );
int4 trialSize = entry.getSize();
Address addr = entry.getAddrBySlot(tmpStatus[entry.getGroup()], trialSize,1);
tmpStatus[entry.getGroup()] = -1; // Consume the register
pieces.push_back(VarnodeData());
pieces.back().space = addr.getSpace();
pieces.back().offset = addr.getOffset();
pieces.back().size = trialSize;
sizeLeft -= trialSize;
}
if (sizeLeft < 0) { // Have odd data-type size
if (justifyRight) {
pieces.front().offset += -sizeLeft; // Initial bytes of first entry are padding
pieces.front().size += sizeLeft;
}
else {
pieces.back().size += sizeLeft;
}
}
status = tmpStatus; // Commit resource usage for all the pieces
res.flags = 0;
res.type = dt;
if (pieces.size() == 1) {
res.addr = pieces[0].getAddr();
return success;
}
if (!consumeMostSig) {
vector<VarnodeData> reverse;
for(int4 i=pieces.size()-1;i>=0;--i)
reverse.push_back(pieces[i]);
pieces.swap(reverse);
}
JoinRecord *joinRecord = tlist.getArch()->findAddJoin(pieces, 0);
res.addr = joinRecord->getUnified().getAddr();
return success;
}
bool MultiSlotDualAssign::fillinOutputMap(ParamActive *active) const
{
int4 count = 0;
int4 curGroup = -1;
int4 partial = -1;
type_class resourceType = TYPECLASS_GENERAL;
for(int4 i=0;i<active->getNumTrials();++i) {
ParamTrial &trial(active->getTrial(i));
const ParamEntry *entry = trial.getEntry();
if (entry == (const ParamEntry *)0) break;
if (count == 0) {
resourceType = entry->getType();
if (resourceType != baseType && resourceType != altType)
return false;
}
else if (entry->getType() != resourceType) // Trials must come from action's type_class
return false;
if (count == 0) {
if (!entry->isFirstInClass())
return false; // Trials must start on first entry of the type_class
}
else {
if (entry->getGroup() != curGroup + 1) // Trials must be consecutive
return false;
}
curGroup = entry->getGroup();
if (trial.getSize() != entry->getSize()) {
if (partial != -1)
return false; // At most, one trial can be partial size
partial = i;
}
count += 1;
}
if (partial != -1) {
if (justifyRight) {
if (partial != 0) return false;
}
else {
if (partial != count - 1) return false;
}
ParamTrial &trial(active->getTrial(partial));
if (justifyRight == consumeMostSig) {
if (trial.getOffset() != 0)
return false; // Partial entry must be least sig bytes
}
else {
if (trial.getOffset() + trial.getSize() != trial.getEntry()->getSize()) {
return false; // Partial entry must be most sig bytes
}
}
}
return (count > 0);
}
void MultiSlotDualAssign::decode(Decoder &decoder)
{
uint4 elemId = decoder.openElement(ELEM_JOIN_DUAL_CLASS);
for(;;) {
uint4 attribId = decoder.getNextAttributeId();
if (attribId == 0) break;
if (attribId == ATTRIB_REVERSEJUSTIFY) {
if (decoder.readBool())
justifyRight = !justifyRight;
}
else if (attribId == ATTRIB_STORAGE || attribId == ATTRIB_A) {
baseType = string2typeclass(decoder.readString());
}
else if (attribId == ATTRIB_B) {
altType = string2typeclass(decoder.readString());
}
}
decoder.closeElement(elemId);
initializeEntries(); // Need new firstIter
}
ConsumeAs::ConsumeAs(type_class store,const ParamListStandard *res)
: AssignAction(res)
{
resourceType = store;
fillinOutputActive = true;
}
uint4 ConsumeAs::assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
@ -713,6 +1188,27 @@ uint4 ConsumeAs::assignAddress(Datatype *dt,const PrototypePieces &proto,int4 po
return resource->assignAddressFallback(resourceType, dt, true, status, res);
}
bool ConsumeAs::fillinOutputMap(ParamActive *active) const
{
int4 count = 0;
for(int4 i=0;i<active->getNumTrials();++i) {
ParamTrial &trial(active->getTrial(i));
const ParamEntry *entry = trial.getEntry();
if (entry == (const ParamEntry *)0) break;
if (entry->getType() != resourceType) // Trials must come from action's type_class
return false;
if (!entry->isFirstInClass())
return false;
count += 1;
if (count > 1)
return false;
if (trial.getOffset() != 0)
return false; // Entry must be justified
}
return (count > 0);
}
void ConsumeAs::decode(Decoder &decoder)
{
@ -761,17 +1257,8 @@ void HiddenReturnAssign::decode(Decoder &decoder)
void ConsumeExtra::initializeEntries(void)
{
const list<ParamEntry> &entries(resource->getEntry());
firstIter = entries.end();
list<ParamEntry>::const_iterator iter;
for(iter=entries.begin();iter!=entries.end();++iter) {
const ParamEntry &entry( *iter );
if (entry.isExclusion() && entry.getType() == resourceType && entry.getAllGroups().size() == 1) {
firstIter = iter; // First matching resource size
break;
}
}
if (firstIter == entries.end())
firstIter = resource->getFirstIter(resourceType);
if (firstIter == resource->getEntry().end())
throw LowlevelError("Could not find matching resources for action: consumeextra");
}