void tweak_booleans1(int p)  // add != 0 where needed
{
  int i;
  int disp;
  int this;
  int cond;

  // recursively search for more "&&" and "||"s throughout the code:
  disp = op[astop(p)-AST_BASE].Display_Children;
  this = 1<<(children(p)-1);
  for (i = 0; i < children(p); i++) {
    if ((nthchild(p, i) != -1) && (disp&this)) {
      if (astop(nthchild(p, i)) != AST_TYPE_Struct)
        {tweak_booleans1(nthchild(p, i)); fixup(nthchild(p, i));}
    }
    this = this>>1;
  }

  // if the condition did not have an explicit comparison at the root,
  // then add an implied "!= 0" (although there's a chance for
  // optimisation here if the operand is already coerced into a
  // proper boolean, -1 or 0)

  if ((AST_ShortcutBoolAnd == astop(p)) || (astop(p) == AST_ShortcutBoolOr)) {
    cond = leftchild(p);
    if ((astop(cond) < AST_LE) || (astop(cond) > AST_NE)) {
      if ((astop(cond) != AST_ShortcutBoolAnd) && (astop(cond) != AST_ShortcutBoolOr)) {
        if (astop(cond) != AST_UBoolNot) {
	  cond = mkbinop(AST_NE, cond, mkconst(0));
          leftchild(p) = cond;
	}
      }
    }
    cond = rightchild(p);
    if ((astop(cond) < AST_LE) || (astop(cond) > AST_NE)) {
      if ((astop(cond) != AST_ShortcutBoolAnd) && (astop(cond) != AST_ShortcutBoolOr)) {
        if (astop(cond) != AST_UBoolNot) {
	  cond = mkbinop(AST_NE, cond, mkconst(0));
          rightchild(p) = cond;
	}
      }
    }
  } else if (astop(p) == AST_C_While) {
    cond = leftchild(p);
    if ((astop(cond) < AST_LE) || (astop(cond) > AST_NE)) {
      if ((astop(cond) != AST_ShortcutBoolAnd) && (astop(cond) != AST_ShortcutBoolOr)) {
        if (astop(cond) != AST_UBoolNot) {
	  cond = mkbinop(AST_NE, cond, mkconst(0));
          leftchild(p) = cond;
	}
      }
    }
  } else if (astop(p) == AST_C_DoWhile) {
    cond = rightchild(p);
    if ((astop(cond) < AST_LE) || (astop(cond) > AST_NE)) {
      if ((astop(cond) != AST_ShortcutBoolAnd) && (astop(cond) != AST_ShortcutBoolOr)) {
        if (astop(cond) != AST_UBoolNot) {
	  cond = mkbinop(AST_NE, cond, mkconst(0));
          rightchild(p) = cond;
	}
      }
    }
  } else if (astop(p) == AST_C_ForLoop) {
    cond = rightchild(p);
    if ((astop(cond) < AST_LE) || (astop(cond) > AST_NE)) {
      if ((astop(cond) != AST_ShortcutBoolAnd) && (astop(cond) != AST_ShortcutBoolOr)) {
        if (astop(cond) != AST_UBoolNot) {
	  cond = mkbinop(AST_NE, cond, mkconst(0));
          rightchild(p) = cond;
	}
      }
    }
  } else if (astop(p) == AST_IFTHENELSE) {
    cond = leftchild(p);
    if ((astop(cond) < AST_LE) || (astop(cond) > AST_NE)) {
      if ((astop(cond) != AST_ShortcutBoolAnd) && (astop(cond) != AST_ShortcutBoolOr)) {
        if (astop(cond) != AST_UBoolNot) {
	  cond = mkbinop(AST_NE, cond, mkconst(0));
          leftchild(p) = cond;
	}
      }
    }
  } else if (astop(p) == AST_IFTHEN) {   //  picks up statements like:   if (!(a < b))) ...; 
    cond = leftchild(p);
    if ((astop(cond) < AST_LE) || (astop(cond) > AST_NE)) {
      if ((astop(cond) != AST_ShortcutBoolAnd) && (astop(cond) != AST_ShortcutBoolOr)) {
        if (astop(cond) != AST_UBoolNot) {
	  cond = mkbinop(AST_NE, cond, mkconst(0));
          leftchild(p) = cond;
	}
      }
    }
  } else if (astop(p) == AST_Cond) {
    cond = leftchild(p);
    if ((astop(cond) < AST_LE) || (astop(cond) > AST_NE)) {
      if ((astop(cond) != AST_ShortcutBoolAnd) && (astop(cond) != AST_ShortcutBoolOr)) {
        if (astop(cond) != AST_UBoolNot) {
	  cond = mkbinop(AST_NE, cond, mkconst(0));
          leftchild(p) = cond;
	}
      }
    }
  }
}

void tweak_booleans2(int p)  // propogate (!(x)) if possible
{
  int i;
  int disp;
  int this;
  int cond;

  // simple_tests/boolean1.c is currently buggy.   "if (!(!x)) ..."

  // recursively search for more opportunities to un-negate easy conditions
  disp = op[astop(p)-AST_BASE].Display_Children;
  this = 1<<(children(p)-1);
  for (i = 0; i < children(p); i++) {
    if ((nthchild(p, i) != -1) && (disp&this)) {
      if (astop(nthchild(p, i)) != AST_TYPE_Struct)  
        {tweak_booleans2(nthchild(p, i)); fixup(nthchild(p, i));}
    }
    this = this>>1;
  }

  if (AST_UBoolNot == astop(p)) {
      cond = leftchild(p);
      if ((astop(cond) >= AST_LE) && (astop(cond) <= AST_NE)) {
        int regular_op[6] = {AST_LE, AST_GT, AST_LT, AST_GE, AST_EQ, AST_NE};
        int negate_op[6] = {AST_GT, AST_LE, AST_GE, AST_LT, AST_NE, AST_EQ};
        assert(regular_op[astop(cond)-AST_LE] == astop(cond));
	//astop(cond) = negate_op[astop(cond)-AST_LE];
        replace_with_trip(p, mkbinop(negate_op[astop(cond)-AST_LE], leftchild(cond), rightchild(cond)));
   // } else if (astop(cond) == AST_UBoolNot) { ... remove double negation?  Or is !(!x) a good shorthand for canonicalising a boolean?
                                                                          // (yes, that's what gcc does)
      } else {
        // something like if (!a) ...  replace with 'a == 0'?
      }
  } else if (astop(p) == AST_IFTHENELSE) {
      while (astop(leftchild(p)) == AST_UBoolNot) { // if (!(condition)) a; else b; -> if (condition) b; else a;
        int tmp = nthchild(p,2);
        nthchild(p,2) = rightchild(p);
        rightchild(p) = tmp;
        leftchild(p) = leftchild(leftchild(p));
      }
      // currently similar hack for IFTHEN is being done in code generator and seems to work but probably shouldn't
  }
}

void tweak_booleans3(int p, int insert_cond_needed)
{
  // insert (x ? TRUE : FALSE) around any conditions that
  // are not handled by short-circuit jumps at obvious places
  int q;
  int r;
  int i;
  int disp;
  int this;
  int cond;

  // remember that once wrapped, recurse on the condition with ,TRUE
  if (((astop(p) >= AST_LE) && (astop(p) <= AST_NE))
   || ((astop(p) == AST_ShortcutBoolAnd) || (astop(p) == AST_ShortcutBoolOr))) {
    if (insert_cond_needed) {
      r = clone(p);
      tweak_booleans3(leftchild(r), FALSE);
      tweak_booleans3(rightchild(r), FALSE);
      q = mkterop(AST_Cond, r, mkconst(TRUE), mkconst(FALSE));
      replace_with_trip(p, q);
    } else {
      tweak_booleans3(leftchild(p), FALSE);   // THIS CODE NEEDS TO BE REVIEWED re TRUE/FALSE being passed on to next level
      tweak_booleans3(rightchild(p), FALSE);
    }
  } else if (AST_UBoolNot == astop(p)) {
    if (insert_cond_needed) {
      r = clone(p);
      tweak_booleans3(leftchild(r), FALSE);
      q = mkterop(AST_Cond, r, mkconst(TRUE), mkconst(FALSE));
      replace_with_trip(p, q);
    } else {
      tweak_booleans3(leftchild(p), FALSE);
    }
  } else if (astop(p) == AST_C_While) {
    cond = leftchild(p);
    tweak_booleans3(cond, FALSE);

    tweak_booleans3(rightchild(p), TRUE);
  } else if (astop(p) == AST_C_DoWhile) {
    cond = rightchild(p);
    tweak_booleans3(cond, FALSE);

    tweak_booleans3(leftchild(p), TRUE);
  } else if (astop(p) == AST_C_ForLoop) {
    cond = rightchild(p);
    tweak_booleans3(cond, FALSE);

    tweak_booleans3(leftchild(p), TRUE);
    tweak_booleans3(nthchild(p,2), TRUE);
    tweak_booleans3(nthchild(p,3), TRUE);
  } else if (astop(p) == AST_IFTHENELSE) {
    cond = leftchild(p);
    tweak_booleans3(cond, FALSE);

    tweak_booleans3(rightchild(p), TRUE);
    tweak_booleans3(nthchild(p,2), TRUE);
  } else if (astop(p) == AST_IFTHEN) {   //  picks up statements like:   if (!(a < b))) ...; 
    cond = leftchild(p);
    tweak_booleans3(cond, FALSE);

    tweak_booleans3(rightchild(p), TRUE);
  } else if (astop(p) == AST_Cond) {
    cond = leftchild(p);
    tweak_booleans3(cond, FALSE);

    tweak_booleans3(rightchild(p), TRUE);
    tweak_booleans3(nthchild(p,2), TRUE);
  } else {
    // recursively search for more opportunities to un-negate easy conditions
    disp = op[astop(p)-AST_BASE].Display_Children;
    this = 1<<(children(p)-1);
    for (i = 0; i < children(p); i++) {
      if ((nthchild(p, i) != -1) && (disp&this)) {
        if (astop(nthchild(p, i)) != AST_TYPE_Struct)
          tweak_booleans3(nthchild(p, i), TRUE);
      }
      this = this>>1;
    }
  }
}

void tweak_booleans(int p)  // add != 0 where needed
{
  tweak_booleans1(p);
  tweak_booleans2(p);
  tweak_booleans3(p, TRUE);  // no idea what this is initialised to.  forgot already!
}
