/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "slghpattern.hh"
#include "slaformat.hh"

namespace ghidra {

uintm DisjointPattern::getMask(int4 startbit,int4 size,bool context) const

{
  PatternBlock *block = getBlock(context);
  if (block != (PatternBlock *)0)
    return block->getMask(startbit,size);
  return 0;
}

uintm DisjointPattern::getValue(int4 startbit,int4 size,bool context) const

{
  PatternBlock *block = getBlock(context);
  if (block != (PatternBlock *)0)
    return block->getValue(startbit,size);
  return 0;
}

int4 DisjointPattern::getLength(bool context) const

{
  PatternBlock *block = getBlock(context);
  if (block != (PatternBlock *)0)
    return block->getLength();
  return 0;
}

bool DisjointPattern::specializes(const DisjointPattern *op2) const

{				// Return true, if everywhere this's mask is non-zero
				// op2's mask is non-zero and op2's value match this's
  PatternBlock *a,*b;

  a = getBlock(false);
  b = op2->getBlock(false);
  if ((b != (PatternBlock *)0)&&(!b->alwaysTrue())) {	// a must match existing block
    if (a == (PatternBlock *)0) return false;
    if (!a->specializes(b)) return false;
  }
  a = getBlock(true);
  b = op2->getBlock(true);
  if ((b != (PatternBlock *)0)&&(!b->alwaysTrue())) {	// a must match existing block
    if (a == (PatternBlock *)0) return false;
    if (!a->specializes(b)) return false;
  }
  return true;
}

bool DisjointPattern::identical(const DisjointPattern *op2) const

{				// Return true if patterns match exactly
  PatternBlock *a,*b;
  
  a = getBlock(false);
  b = op2->getBlock(false);
  if (b != (PatternBlock *)0) {	// a must match existing block
    if (a == (PatternBlock *)0) {
      if (!b->alwaysTrue())
	return false;
    }
    else if (!a->identical(b))
      return false;
  }
  else {
    if ((a != (PatternBlock *)0)&&(!a->alwaysTrue()))
      return false;
  }
  a = getBlock(true);
  b = op2->getBlock(true);
  if (b != (PatternBlock *)0) {	// a must match existing block
    if (a == (PatternBlock *)0) {
      if (!b->alwaysTrue())
	return false;
    }
    else if (!a->identical(b))
      return false;
  }
  else {
    if ((a != (PatternBlock *)0)&&(!a->alwaysTrue()))
      return false;
  }
  return true;
}

static bool resolveIntersectBlock(PatternBlock *bl1,PatternBlock *bl2,PatternBlock *thisblock)

{
  PatternBlock *inter;
  bool allocated = false;
  bool res = true;

  if (bl1 == (PatternBlock *)0)
    inter = bl2;
  else if (bl2 == (PatternBlock *)0)
    inter = bl1;
  else {
    allocated = true;
    inter = bl1->intersect(bl2);
  }
  if (inter == (PatternBlock *)0) {
    if (thisblock != (PatternBlock *)0)
      res = false;
  }
  else if (thisblock == (PatternBlock *)0)
    res = false;
  else
    res = thisblock->identical(inter);
  if (allocated)
    delete inter;
  return res;
}

bool DisjointPattern::resolvesIntersect(const DisjointPattern *op1,const DisjointPattern *op2) const

{ // Is this pattern equal to the intersection of -op1- and -op2-
  if (!resolveIntersectBlock(op1->getBlock(false),op2->getBlock(false),getBlock(false)))
    return false;
  return resolveIntersectBlock(op1->getBlock(true),op2->getBlock(true),getBlock(true));
}

DisjointPattern *DisjointPattern::decodeDisjoint(Decoder &decoder)

{				// DisjointPattern factory
  DisjointPattern *res;
  uint4 el = decoder.peekElement();
  if (el == sla::ELEM_INSTRUCT_PAT)
    res = new InstructionPattern();
  else if (el == sla::ELEM_CONTEXT_PAT)
    res = new ContextPattern();
  else
    res = new CombinePattern();
  res->decode(decoder);
  return res;
}

void PatternBlock::normalize(void)

{
  if (nonzerosize<=0) {		// Check if alwaystrue or alwaysfalse
    offset = 0;			// in which case we don't need mask and value
    maskvec.clear();
    valvec.clear();
    return;
  }
  vector<uintm>::iterator iter1,iter2;
  
  iter1 = maskvec.begin();	// Cut zeros from beginning of mask
  iter2 = valvec.begin();
  while((iter1 != maskvec.end())&&((*iter1)==0)) {
    iter1++;
    iter2++;
    offset += sizeof(uintm);
  }
  maskvec.erase(maskvec.begin(),iter1);
  valvec.erase(valvec.begin(),iter2);

  if (!maskvec.empty()) {
    int4 suboff = 0;		// Cut off unaligned zeros from beginning of mask
    uintm tmp = maskvec[0];
    while(tmp != 0) {
      suboff += 1;
      tmp >>= 8;
    }
    suboff = sizeof(uintm)-suboff;
    if (suboff != 0) {
      offset += suboff;		// Slide up maskvec by suboff bytes
      for(int4 i=0;i<maskvec.size()-1;++i) {
	tmp = maskvec[i] << (suboff*8);
	tmp |= (maskvec[i+1] >> ((sizeof(uintm)-suboff)*8));
	maskvec[i] = tmp;
      }
      maskvec.back() <<= suboff*8;
      for(int4 i=0;i<valvec.size()-1;++i) { // Slide up valvec by suboff bytes
	tmp = valvec[i] << (suboff*8);
	tmp |= (valvec[i+1] >> ((sizeof(uintm)-suboff)*8));
	valvec[i] = tmp;
      }
      valvec.back() <<= suboff*8;
    }
    
    iter1 = maskvec.end();	// Cut zeros from end of mask
    iter2 = valvec.end();
    while(iter1 != maskvec.begin()) {
      --iter1;
      --iter2;
      if ((*iter1) != 0) break; // Find last non-zero
    }
    if (iter1 != maskvec.end()) {
      iter1++;			// Find first zero, in last zero chain
      iter2++;
    }
    maskvec.erase(iter1,maskvec.end());
    valvec.erase(iter2,valvec.end());
  }

  if (maskvec.empty()) {
    offset = 0;
    nonzerosize = 0;		// Always true
    return;
  }
  nonzerosize = maskvec.size() * sizeof(uintm);
  uintm tmp = maskvec.back();	// tmp must be nonzero
  while( (tmp&0xff) == 0) {
    nonzerosize -= 1;
    tmp >>= 8;
  }
}

PatternBlock::PatternBlock(int4 off,uintm msk,uintm val)

{				// Define mask and value pattern, confined to one uintm
  offset = off;
  maskvec.push_back(msk);
  valvec.push_back(val);
  nonzerosize = sizeof(uintm);	// Assume all non-zero bytes before normalization
  normalize();
}

PatternBlock::PatternBlock(bool tf)

{
  offset = 0;
  if (tf)
    nonzerosize = 0;
  else
    nonzerosize = -1;
}

PatternBlock::PatternBlock(const PatternBlock *a,const PatternBlock *b)

{				// Construct PatternBlock by ANDing two others together
  PatternBlock *res = a->intersect(b);
  offset = res->offset;
  nonzerosize = res->nonzerosize;
  maskvec = res->maskvec;
  valvec = res->valvec;
  delete res;
}

PatternBlock::PatternBlock(vector<PatternBlock *> &list)

{				// AND several blocks together to construct new block
  PatternBlock *res,*next;

  if (list.empty()) {		// If not ANDing anything
    offset = 0;			// make constructed block always true
    nonzerosize = 0;
    return;
  }
  res = list[0];
  for(int4 i=1;i<list.size();++i) {
    next = res->intersect(list[i]);
    delete res;
    res = next;
  }
  offset = res->offset;
  nonzerosize = res->nonzerosize;
  maskvec = res->maskvec;
  valvec = res->valvec;
  delete res;
}

PatternBlock *PatternBlock::clone(void) const

{
  PatternBlock *res = new PatternBlock(true);

  res->offset = offset;
  res->nonzerosize = nonzerosize;
  res->maskvec = maskvec;
  res->valvec = valvec;
  return res;
}

PatternBlock *PatternBlock::commonSubPattern(const PatternBlock *b) const

{				// The resulting pattern has a 1-bit in the mask
				// only if the two pieces have a 1-bit and the
				// values agree
  PatternBlock *res = new PatternBlock(true);
  int4 maxlength = (getLength() > b->getLength()) ? getLength() : b->getLength();

  res->offset = 0;
  int4 offset = 0;
  uintm mask1,val1,mask2,val2;
  uintm resmask,resval;
  while(offset < maxlength) {
    mask1 = getMask(offset*8,sizeof(uintm)*8);
    val1 = getValue(offset*8,sizeof(uintm)*8);
    mask2 = b->getMask(offset*8,sizeof(uintm)*8);
    val2 = b->getValue(offset*8,sizeof(uintm)*8);
    resmask = mask1 & mask2 & ~(val1^val2);
    resval = val1 & val2 & resmask;
    res->maskvec.push_back(resmask);
    res->valvec.push_back(resval);
    offset += sizeof(uintm);
  }
  res->nonzerosize = maxlength;
  res->normalize();
  return res;
}

PatternBlock *PatternBlock::intersect(const PatternBlock *b) const

{ // Construct the intersecting pattern
  if (alwaysFalse() || b->alwaysFalse())
    return new PatternBlock(false);
  PatternBlock *res = new PatternBlock(true);
  int4 maxlength = (getLength() > b->getLength()) ? getLength() : b->getLength();

  res->offset = 0;
  int4 offset = 0;
  uintm mask1,val1,mask2,val2,commonmask;
  uintm resmask,resval;
  while(offset < maxlength) {
    mask1 = getMask(offset*8,sizeof(uintm)*8);
    val1 = getValue(offset*8,sizeof(uintm)*8);
    mask2 = b->getMask(offset*8,sizeof(uintm)*8);
    val2 = b->getValue(offset*8,sizeof(uintm)*8);
    commonmask = mask1 & mask2;	// Bits in mask shared by both patterns
    if ((commonmask & val1) != (commonmask & val2)) {
      res->nonzerosize = -1;	// Impossible pattern
      res->normalize();
      return res;
    }
    resmask = mask1 | mask2;
    resval = (mask1 & val1) | (mask2 & val2);
    res->maskvec.push_back(resmask);
    res->valvec.push_back(resval);
    offset += sizeof(uintm);
  }
  res->nonzerosize = maxlength;
  res->normalize();
  return res;
}

bool PatternBlock::specializes(const PatternBlock *op2) const

{				// does every masked bit in -this- match the corresponding
				// masked bit in -op2-
  int4 length = 8*op2->getLength();
  int4 tmplength;
  uintm mask1,mask2,value1,value2;
  int4 sbit = 0;
  while(sbit < length) {
    tmplength = length-sbit;
    if (tmplength > 8*sizeof(uintm))
      tmplength = 8*sizeof(uintm);
    mask1 = getMask(sbit,tmplength);
    value1 = getValue(sbit,tmplength);
    mask2 = op2->getMask(sbit,tmplength);
    value2 = op2->getValue(sbit,tmplength);
    if ((mask1 & mask2) != mask2) return false;
    if ((value1 & mask2) != (value2 & mask2)) return false;
    sbit += tmplength;
  }
  return true;
}

bool PatternBlock::identical(const PatternBlock *op2) const

{				// Do the mask and value match exactly
  int4 tmplength;
  int4 length = 8*op2->getLength();
  tmplength = 8*getLength();
  if (tmplength > length)
    length = tmplength;		// Maximum of two lengths
  uintm mask1,mask2,value1,value2;
  int4 sbit = 0;
  while(sbit < length) {
    tmplength = length-sbit;
    if (tmplength > 8*sizeof(uintm))
      tmplength = 8*sizeof(uintm);
    mask1 = getMask(sbit,tmplength);
    value1 = getValue(sbit,tmplength);
    mask2 = op2->getMask(sbit,tmplength);
    value2 = op2->getValue(sbit,tmplength);
    if (mask1 != mask2) return false;
    if ((mask1&value1) != (mask2&value2)) return false;
    sbit += tmplength;
  }
  return true;
}

uintm PatternBlock::getMask(int4 startbit,int4 size) const

{
  startbit -= 8*offset;
  // Note the division and remainder here is unsigned.  Then it is recast to signed. 
  // If startbit is negative, then wordnum1 is either negative or very big,
  // if (unsigned size is same as sizeof int)
  // In either case, shift should come out between 0 and 8*sizeof(uintm)-1
  int4 wordnum1 = startbit/(8*sizeof(uintm));
  int4 shift = startbit % (8*sizeof(uintm));
  int4 wordnum2 = (startbit+size-1)/(8*sizeof(uintm));
  uintm res;

  if ((wordnum1<0)||(wordnum1>=maskvec.size()))
    res = 0;
  else
    res = maskvec[wordnum1];

  res <<= shift;
  if (wordnum1 != wordnum2) {
    uintm tmp;
    if ((wordnum2<0)||(wordnum2>=maskvec.size()))
      tmp = 0;
    else
      tmp = maskvec[wordnum2];
    res |= (tmp>>(8*sizeof(uintm)-shift));
  }
  res >>= (8*sizeof(uintm) - size);
  
  return res;
}

uintm PatternBlock::getValue(int4 startbit,int4 size) const

{
  startbit -= 8*offset;
  int4 wordnum1 = startbit/(8*sizeof(uintm));
  int4 shift = startbit % (8*sizeof(uintm));
  int4 wordnum2 = (startbit+size-1)/(8*sizeof(uintm));
  uintm res;

  if ((wordnum1<0)||(wordnum1>=valvec.size()))
    res = 0;
  else
    res = valvec[wordnum1];
  res <<= shift;
  if (wordnum1 != wordnum2) {
    uintm tmp;
    if ((wordnum2<0)||(wordnum2>=valvec.size()))
      tmp = 0;
    else
      tmp = valvec[wordnum2];
    res |= (tmp>>(8*sizeof(uintm)-shift));
  }
  res >>= (8*sizeof(uintm) - size);
  
  return res;
}

bool PatternBlock::isInstructionMatch(ParserWalker &walker) const

{
  if (nonzerosize<=0) return (nonzerosize==0);
  int4 off = offset;
  for(int4 i=0;i<maskvec.size();++i) {
    uintm data = walker.getInstructionBytes(off,sizeof(uintm));
    if ((maskvec[i] & data)!=valvec[i]) return false;
    off += sizeof(uintm);
  }
  return true;
}

bool PatternBlock::isContextMatch(ParserWalker &walker) const

{
  if (nonzerosize<=0) return (nonzerosize==0);
  int4 off = offset;
  for(int4 i=0;i<maskvec.size();++i) {
    uintm data = walker.getContextBytes(off,sizeof(uintm));
    if ((maskvec[i] & data)!=valvec[i]) return false;
    off += sizeof(uintm);
  }
  return true;
}

void PatternBlock::encode(Encoder &encoder) const

{
  encoder.openElement(sla::ELEM_PAT_BLOCK);
  encoder.writeSignedInteger(sla::ATTRIB_OFF, offset);
  encoder.writeSignedInteger(sla::ATTRIB_NONZERO, nonzerosize);
  for(int4 i=0;i<maskvec.size();++i) {
    encoder.openElement(sla::ELEM_MASK_WORD);
    encoder.writeUnsignedInteger(sla::ATTRIB_MASK, maskvec[i]);
    encoder.writeUnsignedInteger(sla::ATTRIB_VAL, valvec[i]);
    encoder.closeElement(sla::ELEM_MASK_WORD);
  }
  encoder.closeElement(sla::ELEM_PAT_BLOCK);
}

void PatternBlock::decode(Decoder &decoder)

{
  uint4 el = decoder.openElement(sla::ELEM_PAT_BLOCK);
  offset = decoder.readSignedInteger(sla::ATTRIB_OFF);
  nonzerosize = decoder.readSignedInteger(sla::ATTRIB_NONZERO);
  while(decoder.peekElement() != 0) {
    uint4 subel = decoder.openElement(sla::ELEM_MASK_WORD);
    uintm mask = decoder.readUnsignedInteger(sla::ATTRIB_MASK);
    uintm val = decoder.readUnsignedInteger(sla::ATTRIB_VAL);
    maskvec.push_back(mask);
    valvec.push_back(val);
    decoder.closeElement(subel);
  }
  normalize();
  decoder.closeElement(el);
}

Pattern *InstructionPattern::doAnd(const Pattern *b,int4 sa) const

{
  if (b->numDisjoint()>0)
    return b->doAnd(this,-sa);

  const CombinePattern *b2 = dynamic_cast<const CombinePattern *>(b);
  if (b2 != (const CombinePattern *)0)
    return b->doAnd(this,-sa);

  const ContextPattern *b3 = dynamic_cast<const ContextPattern *>(b);
  if (b3 != (const ContextPattern *)0) {
    InstructionPattern *newpat = (InstructionPattern *)simplifyClone();
    if (sa < 0)
      newpat->shiftInstruction(-sa);
    return new CombinePattern((ContextPattern *)b3->simplifyClone(),newpat);
  }
  const InstructionPattern *b4 = (const InstructionPattern *)b;

  PatternBlock *respattern;
  if (sa < 0) {
    PatternBlock *a = maskvalue->clone();
    a->shift(-sa);
    respattern = a->intersect(b4->maskvalue);
    delete a;
  }
  else {
    PatternBlock *c = b4->maskvalue->clone();
    c->shift(sa);
    respattern = maskvalue->intersect(c);
    delete c;
  }
  return new InstructionPattern(respattern);
}

Pattern *InstructionPattern::commonSubPattern(const Pattern *b,int4 sa) const

{
  if (b->numDisjoint()>0)
    return b->commonSubPattern(this,-sa);

  const CombinePattern *b2 = dynamic_cast<const CombinePattern *>(b);
  if (b2 != (const CombinePattern *)0)
    return b->commonSubPattern(this,-sa);

  const ContextPattern *b3 = dynamic_cast<const ContextPattern *>(b);
  if (b3 != (const ContextPattern *)0) {
    InstructionPattern *res = new InstructionPattern(true);
    return res;
  }
  const InstructionPattern *b4 = (const InstructionPattern *)b;
  
  PatternBlock *respattern;
  if (sa < 0) {
    PatternBlock *a = maskvalue->clone();
    a->shift(-sa);
    respattern = a->commonSubPattern(b4->maskvalue);
    delete a;
  }
  else {
    PatternBlock *c = b4->maskvalue->clone();
    c->shift(sa);
    respattern = maskvalue->commonSubPattern(c);
    delete c;
  }
  return new InstructionPattern(respattern);
}

Pattern *InstructionPattern::doOr(const Pattern *b,int4 sa) const

{
  if (b->numDisjoint()>0)
    return b->doOr(this,-sa);

  const CombinePattern *b2 = dynamic_cast<const CombinePattern *>(b);
  if (b2 != (const CombinePattern *)0)
    return b->doOr(this,-sa);

  DisjointPattern *res1,*res2;
  res1 = (DisjointPattern *)simplifyClone();
  res2 = (DisjointPattern *)b->simplifyClone();
  if (sa < 0)
    res1->shiftInstruction(-sa);
  else
    res2->shiftInstruction(sa);
  return new OrPattern(res1,res2);
}

void InstructionPattern::encode(Encoder &encoder) const

{
  encoder.openElement(sla::ELEM_INSTRUCT_PAT);
  maskvalue->encode(encoder);
  encoder.closeElement(sla::ELEM_INSTRUCT_PAT);
}

void InstructionPattern::decode(Decoder &decoder)

{
  uint4 el = decoder.openElement(sla::ELEM_INSTRUCT_PAT);
  maskvalue = new PatternBlock(true);
  maskvalue->decode(decoder);
  decoder.closeElement(el);
}

Pattern *ContextPattern::doOr(const Pattern *b,int4 sa) const

{
  const ContextPattern *b2 = dynamic_cast<const ContextPattern *>(b);
  if (b2 == (const ContextPattern *)0)
    return b->doOr(this,-sa);

  return new OrPattern((DisjointPattern *)simplifyClone(),(DisjointPattern *)b2->simplifyClone());
}

Pattern *ContextPattern::doAnd(const Pattern *b,int4 sa) const

{
  const ContextPattern *b2 = dynamic_cast<const ContextPattern *>(b);
  if (b2 == (const ContextPattern *)0)
    return b->doAnd(this,-sa);

  PatternBlock *resblock = maskvalue->intersect(b2->maskvalue);
  return new ContextPattern(resblock);
}

Pattern *ContextPattern::commonSubPattern(const Pattern *b,int4 sa) const

{
  const ContextPattern *b2 = dynamic_cast<const ContextPattern *>(b);
  if (b2 == (const ContextPattern *)0)
    return b->commonSubPattern(this,-sa);

  PatternBlock *resblock = maskvalue->commonSubPattern(b2->maskvalue);
  return new ContextPattern(resblock);
}

void ContextPattern::encode(Encoder &encoder) const

{
  encoder.openElement(sla::ELEM_CONTEXT_PAT);
  maskvalue->encode(encoder);
  encoder.closeElement(sla::ELEM_CONTEXT_PAT);
}

void ContextPattern::decode(Decoder &decoder)

{
  uint4 el = decoder.openElement(sla::ELEM_CONTEXT_PAT);
  maskvalue = new PatternBlock(true);
  maskvalue->decode(decoder);
  decoder.closeElement(el);
}

CombinePattern::~CombinePattern(void)

{
  if (context != (ContextPattern *)0)
    delete context;
  if (instr != (InstructionPattern *)0)
    delete instr;
}

bool CombinePattern::isMatch(ParserWalker &walker) const

{
  if (!instr->isMatch(walker)) return false;
  if (!context->isMatch(walker)) return false;
  return true;
}

bool CombinePattern::alwaysTrue(void) const

{
  return (context->alwaysTrue() && instr->alwaysTrue());
}

bool CombinePattern::alwaysFalse(void) const

{
  return (context->alwaysFalse() || instr->alwaysFalse());
}

Pattern *CombinePattern::doAnd(const Pattern *b,int4 sa) const

{
  CombinePattern *tmp;
  
  if (b->numDisjoint() != 0)
    return b->doAnd(this,-sa);

  const CombinePattern *b2 = dynamic_cast<const CombinePattern *>(b);
  if (b2 != (CombinePattern *)0) {
    ContextPattern *c = (ContextPattern *)context->doAnd(b2->context,0);
    InstructionPattern *i = (InstructionPattern *)instr->doAnd(b2->instr,sa);
    tmp = new CombinePattern(c,i);
  }
  else {
    const InstructionPattern *b3 = dynamic_cast<const InstructionPattern *>(b);
    if (b3 != (const InstructionPattern *)0) {
      InstructionPattern *i = (InstructionPattern *)instr->doAnd(b3,sa);
      tmp = new CombinePattern((ContextPattern *)context->simplifyClone(),i);
    }
    else {			// Must be a ContextPattern
      ContextPattern *c = (ContextPattern *)context->doAnd(b,0);
      InstructionPattern *newpat = (InstructionPattern *) instr->simplifyClone();
      if (sa < 0)
	newpat->shiftInstruction(-sa);
      tmp = new CombinePattern(c,newpat);
    }
  }
  return tmp;
}

Pattern *CombinePattern::commonSubPattern(const Pattern *b,int4 sa) const

{
  Pattern *tmp;

  if (b->numDisjoint() != 0)
    return b->commonSubPattern(this,-sa);

  const CombinePattern *b2 = dynamic_cast<const CombinePattern *>(b);
  if (b2 != (CombinePattern *)0) {
    ContextPattern *c = (ContextPattern *)context->commonSubPattern(b2->context,0);
    InstructionPattern *i = (InstructionPattern *)instr->commonSubPattern(b2->instr,sa);
    tmp = new CombinePattern(c,i);
  }
  else {
    const InstructionPattern *b3 = dynamic_cast<const InstructionPattern *>(b);
    if (b3 != (const InstructionPattern *)0)
      tmp = instr->commonSubPattern(b3,sa);
    else			// Must be a ContextPattern
      tmp = context->commonSubPattern(b,0);
  }
  return tmp;
}

Pattern *CombinePattern::doOr(const Pattern *b,int4 sa) const

{
  if (b->numDisjoint() != 0)
    return b->doOr(this,-sa);

  DisjointPattern *res1 = (DisjointPattern *)simplifyClone();
  DisjointPattern *res2 = (DisjointPattern *)b->simplifyClone();
  if (sa < 0)
    res1->shiftInstruction(-sa);
  else
    res2->shiftInstruction(sa);
  OrPattern *tmp = new OrPattern(res1,res2);
  return tmp;
}

Pattern *CombinePattern::simplifyClone(void) const

{				// We should only have to think at "our" level
  if (context->alwaysTrue())
    return instr->simplifyClone();
  if (instr->alwaysTrue())
    return context->simplifyClone();
  if (context->alwaysFalse()||instr->alwaysFalse())
    return new InstructionPattern(false);
  return new CombinePattern((ContextPattern *)context->simplifyClone(),
			    (InstructionPattern *)instr->simplifyClone());
}

void CombinePattern::encode(Encoder &encoder) const

{
  encoder.openElement(sla::ELEM_COMBINE_PAT);
  context->encode(encoder);
  instr->encode(encoder);
  encoder.closeElement(sla::ELEM_COMBINE_PAT);
}

void CombinePattern::decode(Decoder &decoder)

{
  uint4 el = decoder.openElement(sla::ELEM_COMBINE_PAT);
  context = new ContextPattern();
  context->decode(decoder);
  instr = new InstructionPattern();
  instr->decode(decoder);
  decoder.closeElement(el);
}

OrPattern::OrPattern(DisjointPattern *a,DisjointPattern *b)

{
  orlist.push_back(a);
  orlist.push_back(b);
}

OrPattern::OrPattern(const vector<DisjointPattern *> &list)

{
  vector<DisjointPattern *>::const_iterator iter;

  for(iter=list.begin();iter!=list.end();++iter)
    orlist.push_back(*iter);
}

OrPattern::~OrPattern(void)

{
  vector<DisjointPattern *>::iterator iter;

  for(iter=orlist.begin();iter!=orlist.end();++iter)
    delete *iter;
}

void OrPattern::shiftInstruction(int4 sa)

{
  vector<DisjointPattern *>::iterator iter;

  for(iter=orlist.begin();iter!=orlist.end();++iter)
    (*iter)->shiftInstruction(sa);
}

bool OrPattern::isMatch(ParserWalker &walker) const

{
  for(int4 i=0;i<orlist.size();++i)
    if (orlist[i]->isMatch(walker))
      return true;
  return false;
}

bool OrPattern::alwaysTrue(void) const

{				// This isn't quite right because different branches
				// may cover the entire gamut
  vector<DisjointPattern *>::const_iterator iter;

  for(iter=orlist.begin();iter!=orlist.end();++iter)
    if ((*iter)->alwaysTrue()) return true;
  return false;
}

bool OrPattern::alwaysFalse(void) const

{
  vector<DisjointPattern *>::const_iterator iter;

  for(iter=orlist.begin();iter!=orlist.end();++iter)
    if (!(*iter)->alwaysFalse()) return false;
  return true;
}

bool OrPattern::alwaysInstructionTrue(void) const

{
  vector<DisjointPattern *>::const_iterator iter;

  for(iter=orlist.begin();iter!=orlist.end();++iter)
    if (!(*iter)->alwaysInstructionTrue()) return false;
  return true;
}

Pattern *OrPattern::doAnd(const Pattern *b,int4 sa) const

{
  const OrPattern *b2 = dynamic_cast<const OrPattern *>(b);
  vector<DisjointPattern *> newlist;
  vector<DisjointPattern *>::const_iterator iter,iter2;
  DisjointPattern *tmp;
  OrPattern *tmpor;

  if (b2 == (const OrPattern *)0) {
    for(iter=orlist.begin();iter!=orlist.end();++iter) {
      tmp = (DisjointPattern *)(*iter)->doAnd(b,sa);
      newlist.push_back(tmp);
    }
  }
  else {
    for(iter=orlist.begin();iter!=orlist.end();++iter)
      for(iter2=b2->orlist.begin();iter2!=b2->orlist.end();++iter2) {
	tmp = (DisjointPattern *)(*iter)->doAnd(*iter2,sa);
	newlist.push_back(tmp);
      }
  }
  tmpor = new OrPattern(newlist);
  return tmpor;
}

Pattern *OrPattern::commonSubPattern(const Pattern *b,int4 sa) const

{
  vector<DisjointPattern *>::const_iterator iter;
  Pattern *res,*next;

  iter = orlist.begin();
  res = (*iter)->commonSubPattern(b,sa);
  iter++;

  if (sa > 0)
    sa = 0;
  while(iter!=orlist.end()) {
    next = (*iter)->commonSubPattern(res,sa);
    delete res;
    res = next;
    ++iter;
  }
  return res;
}

Pattern *OrPattern::doOr(const Pattern *b,int4 sa) const

{
  const OrPattern *b2 = dynamic_cast<const OrPattern *>(b);
  vector<DisjointPattern *> newlist;
  vector<DisjointPattern *>::const_iterator iter;

  for(iter=orlist.begin();iter!=orlist.end();++iter)
    newlist.push_back((DisjointPattern *)(*iter)->simplifyClone());
  if (sa < 0)
    for(iter=orlist.begin();iter!=orlist.end();++iter)
      (*iter)->shiftInstruction(-sa);

  if (b2 == (const OrPattern *)0)
    newlist.push_back((DisjointPattern *)b->simplifyClone());
  else {
    for(iter=b2->orlist.begin();iter!=b2->orlist.end();++iter)
      newlist.push_back((DisjointPattern *)(*iter)->simplifyClone());
  }
  if (sa > 0)
    for(int4 i=0;i<newlist.size();++i)
      newlist[i]->shiftInstruction(sa);

  OrPattern *tmpor = new OrPattern(newlist);
  return tmpor;
}

Pattern *OrPattern::simplifyClone(void) const

{				// Look for alwaysTrue eliminate alwaysFalse
  vector<DisjointPattern *>::const_iterator iter;

  for(iter=orlist.begin();iter!=orlist.end();++iter) // Look for alwaysTrue
    if ((*iter)->alwaysTrue())
      return new InstructionPattern(true);

  vector<DisjointPattern *> newlist;
  for(iter=orlist.begin();iter!=orlist.end();++iter) // Look for alwaysFalse
    if (!(*iter)->alwaysFalse())
      newlist.push_back((DisjointPattern *)(*iter)->simplifyClone());
  
  if (newlist.empty())
    return new InstructionPattern(false);
  else if (newlist.size() == 1)
    return newlist[0];
  return new OrPattern(newlist);
}

void OrPattern::encode(Encoder &encoder) const

{
  encoder.openElement(sla::ELEM_OR_PAT);
  for(int4 i=0;i<orlist.size();++i)
    orlist[i]->encode(encoder);
  encoder.closeElement(sla::ELEM_OR_PAT);
}

void OrPattern::decode(Decoder &decoder)

{
  uint4 el = decoder.openElement(sla::ELEM_OR_PAT);
  while(decoder.peekElement() != 0) {
    DisjointPattern *pat = DisjointPattern::decodeDisjoint(decoder);
    orlist.push_back(pat);
  }
  decoder.closeElement(el);
}

} // End namespace ghidra
