| Index: src/IceTargetLoweringMIPS32.cpp | 
| diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp | 
| index cbfad693619260aa00cd2b05f75316550c1e97d7..826296ab9e0a46036263ea3ca5c5b0e8bdfc0994 100644 | 
| --- a/src/IceTargetLoweringMIPS32.cpp | 
| +++ b/src/IceTargetLoweringMIPS32.cpp | 
| @@ -22,6 +22,7 @@ | 
| #include "IceELFObjectWriter.h" | 
| #include "IceGlobalInits.h" | 
| #include "IceInstMIPS32.h" | 
| +#include "IceInstVarIter.h" | 
| #include "IceLiveness.h" | 
| #include "IceOperand.h" | 
| #include "IcePhiLoweringImpl.h" | 
| @@ -813,7 +814,84 @@ void TargetMIPS32::lowerBr(const InstBr *Instr) { | 
| _br(Instr->getTargetUnconditional()); | 
| return; | 
| } | 
| -  UnimplementedLoweringError(this, Instr); | 
| +  CfgNode *TargetTrue = Instr->getTargetTrue(); | 
| +  CfgNode *TargetFalse = Instr->getTargetFalse(); | 
| +  Operand *Boolean = Instr->getCondition(); | 
| +  const Inst *Producer = Computations.getProducerOf(Boolean); | 
| +  if (Producer == nullptr) { | 
| +    // Since we don't know the producer of this boolean we will assume its | 
| +    // producer will keep it in positive logic and just emit beqz with this | 
| +    // Boolean as an operand. | 
| +    auto *BooleanR = legalizeToReg(Boolean); | 
| +    _br(TargetTrue, TargetFalse, BooleanR, CondMIPS32::Cond::EQZ); | 
| +    return; | 
| +  } | 
| +  if (Producer->getKind() == Inst::Icmp) { | 
| +    const InstIcmp *CompareInst = llvm::cast<InstIcmp>(Producer); | 
| +    Operand *Src0 = CompareInst->getSrc(0); | 
| +    Operand *Src1 = CompareInst->getSrc(1); | 
| +    const Type Src0Ty = Src0->getType(); | 
| +    assert(Src0Ty == Src1->getType()); | 
| +    if (Src0Ty == IceType_i64) { | 
| +      UnimplementedLoweringError(this, Instr); | 
| +      return; | 
| +    } | 
| +    auto *Src0R = legalizeToReg(Src0); | 
| +    auto *Src1R = legalizeToReg(Src1); | 
| +    auto *DestT = makeReg(Src0Ty); | 
| +    switch (CompareInst->getCondition()) { | 
| +    default: | 
| +      break; | 
| +    case InstIcmp::Eq: { | 
| +      _br(TargetTrue, TargetFalse, Src0R, Src1R, CondMIPS32::Cond::NE); | 
| +      break; | 
| +    } | 
| +    case InstIcmp::Ne: { | 
| +      _br(TargetTrue, TargetFalse, Src0R, Src1R, CondMIPS32::Cond::EQ); | 
| +      break; | 
| +    } | 
| +    case InstIcmp::Ugt: { | 
| +      _sltu(DestT, Src1R, Src0R); | 
| +      _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ); | 
| +      break; | 
| +    } | 
| +    case InstIcmp::Uge: { | 
| +      _sltu(DestT, Src0R, Src1R); | 
| +      _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); | 
| +      break; | 
| +    } | 
| +    case InstIcmp::Ult: { | 
| +      _sltu(DestT, Src0R, Src1R); | 
| +      _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ); | 
| +      break; | 
| +    } | 
| +    case InstIcmp::Ule: { | 
| +      _sltu(DestT, Src1R, Src0R); | 
| +      _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); | 
| +      break; | 
| +    } | 
| +    case InstIcmp::Sgt: { | 
| +      _slt(DestT, Src1R, Src0R); | 
| +      _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ); | 
| +      break; | 
| +    } | 
| +    case InstIcmp::Sge: { | 
| +      _slt(DestT, Src0R, Src1R); | 
| +      _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); | 
| +      break; | 
| +    } | 
| +    case InstIcmp::Slt: { | 
| +      _slt(DestT, Src0R, Src1R); | 
| +      _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::EQZ); | 
| +      break; | 
| +    } | 
| +    case InstIcmp::Sle: { | 
| +      _slt(DestT, Src1R, Src0R); | 
| +      _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); | 
| +      break; | 
| +    } | 
| +    } | 
| +  } | 
| } | 
|  | 
| void TargetMIPS32::lowerCall(const InstCall *Instr) { | 
| @@ -1031,7 +1109,7 @@ void TargetMIPS32::lowerIcmp(const InstIcmp *Instr) { | 
| case InstIcmp::Sge: { | 
| auto *DestT = I32Reg(); | 
| auto *T = I32Reg(); | 
| -    _slt(T, Src1R, Src0R); | 
| +    _slt(T, Src0R, Src1R); | 
| _xori(DestT, T, 1); | 
| _mov(Dest, DestT); | 
| return; | 
| @@ -1410,6 +1488,72 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed, | 
| return From; | 
| } | 
|  | 
| +namespace BoolFolding { | 
| +// TODO(sagar.thakur): Add remaining instruction kinds to shouldTrackProducer() | 
| +// and isValidConsumer() | 
| +bool shouldTrackProducer(const Inst &Instr) { | 
| +  return Instr.getKind() == Inst::Icmp; | 
| +} | 
| + | 
| +bool isValidConsumer(const Inst &Instr) { return Instr.getKind() == Inst::Br; } | 
| +} // end of namespace BoolFolding | 
| + | 
| +void TargetMIPS32::ComputationTracker::recordProducers(CfgNode *Node) { | 
| +  for (Inst &Instr : Node->getInsts()) { | 
| +    if (Instr.isDeleted()) | 
| +      continue; | 
| +    // Check whether Instr is a valid producer. | 
| +    Variable *Dest = Instr.getDest(); | 
| +    if (Dest // only consider instructions with an actual dest var; and | 
| +        && Dest->getType() == IceType_i1 // only bool-type dest vars; and | 
| +        && BoolFolding::shouldTrackProducer(Instr)) { // white-listed instr. | 
| +      KnownComputations.emplace(Dest->getIndex(), | 
| +                                ComputationEntry(&Instr, IceType_i1)); | 
| +    } | 
| +    // Check each src variable against the map. | 
| +    FOREACH_VAR_IN_INST(Var, Instr) { | 
| +      SizeT VarNum = Var->getIndex(); | 
| +      auto ComputationIter = KnownComputations.find(VarNum); | 
| +      if (ComputationIter == KnownComputations.end()) { | 
| +        continue; | 
| +      } | 
| + | 
| +      ++ComputationIter->second.NumUses; | 
| +      switch (ComputationIter->second.ComputationType) { | 
| +      default: | 
| +        KnownComputations.erase(VarNum); | 
| +        continue; | 
| +      case IceType_i1: | 
| +        if (!BoolFolding::isValidConsumer(Instr)) { | 
| +          KnownComputations.erase(VarNum); | 
| +          continue; | 
| +        } | 
| +        break; | 
| +      } | 
| + | 
| +      if (Instr.isLastUse(Var)) { | 
| +        ComputationIter->second.IsLiveOut = false; | 
| +      } | 
| +    } | 
| +  } | 
| + | 
| +  for (auto Iter = KnownComputations.begin(), End = KnownComputations.end(); | 
| +       Iter != End;) { | 
| +    // Disable the folding if its dest may be live beyond this block. | 
| +    if (Iter->second.IsLiveOut || Iter->second.NumUses > 1) { | 
| +      Iter = KnownComputations.erase(Iter); | 
| +      continue; | 
| +    } | 
| + | 
| +    // Mark as "dead" rather than outright deleting. This is so that other | 
| +    // peephole style optimizations during or before lowering have access to | 
| +    // this instruction in undeleted form. See for example | 
| +    // tryOptimizedCmpxchgCmpBr(). | 
| +    Iter->second.Instr->setDead(); | 
| +    ++Iter; | 
| +  } | 
| +} | 
| + | 
| TargetHeaderMIPS32::TargetHeaderMIPS32(GlobalContext *Ctx) | 
| : TargetHeaderLowering(Ctx) {} | 
|  | 
|  |