Example #1
0
SSATmp* TraceBuilder::optimizeWork(IRInstruction* inst,
                                   const folly::Optional<IdomVector>& idoms) {
    // Since some of these optimizations inspect tracked state, we don't
    // perform any of them on non-main traces.
    if (m_savedTraces.size() > 0) return nullptr;

    static DEBUG_ONLY __thread int instNest = 0;
    if (debug) ++instNest;
    SCOPE_EXIT { if (debug) --instNest; };
DEBUG_ONLY auto indent = [&] { return std::string(instNest * 2, ' '); };

    FTRACE(1, "{}{}\n", indent(), inst->toString());

    // First pass of tracebuilder optimizations try to replace an
    // instruction based on tracked state before we do anything else.
    // May mutate the IRInstruction in place (and return nullptr) or
    // return an SSATmp*.
    if (SSATmp* preOpt = preOptimize(inst)) {
        FTRACE(1, "  {}preOptimize returned: {}\n",
               indent(), preOpt->inst()->toString());
        return preOpt;
    }
    if (inst->op() == Nop) return nullptr;

    // copy propagation on inst source operands
    copyProp(inst);

    SSATmp* result = nullptr;
    if (m_enableCse && inst->canCSE()) {
        result = cseLookup(inst, idoms);
        if (result) {
            // Found a dominating instruction that can be used instead of inst
            FTRACE(1, "  {}cse found: {}\n",
                   indent(), result->inst()->toString());
            assert(!inst->consumesReferences());
            if (inst->producesReference()) {
                // Replace with an IncRef
                FTRACE(1, "  {}cse of refcount-producing instruction\n", indent());
                return gen(IncRef, result);
            } else {
                return result;
            }
        }
    }

    if (m_enableSimplification) {
        result = m_simplifier.simplify(inst);
        if (result) {
            // Found a simpler instruction that can be used instead of inst
            FTRACE(1, "  {}simplification returned: {}\n",
                   indent(), result->inst()->toString());
            assert(inst->hasDst());
            return result;
        }
    }
    return nullptr;
}
Example #2
0
SSATmp* TraceBuilder::optimizeWork(IRInstruction* inst) {
  static DEBUG_ONLY __thread int instNest = 0;
  if (debug) ++instNest;
  SCOPE_EXIT { if (debug) --instNest; };
  DEBUG_ONLY auto indent = [&] { return std::string(instNest * 2, ' '); };

  FTRACE(1, "{}{}\n", indent(), inst->toString());

  // First pass of tracebuilder optimizations try to replace an
  // instruction based on tracked state before we do anything else.
  // May mutate the IRInstruction in place (and return nullptr) or
  // return an SSATmp*.
  if (SSATmp* preOpt = preOptimize(inst)) {
    FTRACE(1, "  {}preOptimize returned: {}\n",
           indent(), preOpt->inst()->toString());
    return preOpt;
  }
  if (inst->op() == Nop) return nullptr;

  // copy propagation on inst source operands
  copyProp(inst);

  SSATmp* result = nullptr;
  if (m_enableCse && inst->canCSE()) {
    result = cseLookup(inst);
    if (result) {
      // Found a dominating instruction that can be used instead of inst
      FTRACE(1, "  {}cse found: {}\n",
             indent(), result->inst()->toString());
      return result;
    }
  }

  if (m_enableSimplification) {
    result = m_simplifier.simplify(inst);
    if (result) {
      // Found a simpler instruction that can be used instead of inst
      FTRACE(1, "  {}simplification returned: {}\n",
             indent(), result->inst()->toString());
      assert(inst->hasDst());
      return result;
    }
  }
  return nullptr;
}
Example #3
0
SSATmp* IRBuilder::optimizeWork(IRInstruction* inst,
                                const folly::Optional<IdomVector>& idoms) {
  // Since some of these optimizations inspect tracked state, we don't
  // perform any of them on non-main traces.
  if (m_savedBlocks.size() > 0) return nullptr;

  static DEBUG_ONLY __thread int instNest = 0;
  if (debug) ++instNest;
  SCOPE_EXIT { if (debug) --instNest; };
  DEBUG_ONLY auto indent = [&] { return std::string(instNest * 2, ' '); };

  FTRACE(1, "optimizing {}{}\n", indent(), inst->toString());

  // First pass of IRBuilder optimizations try to replace an
  // instruction based on tracked state before we do anything else.
  // May mutate the IRInstruction in place (and return nullptr) or
  // return an SSATmp*.
  if (SSATmp* preOpt = preOptimize(inst)) {
    FTRACE(1, "  {}preOptimize returned: {}\n",
           indent(), preOpt->inst()->toString());
    return preOpt;
  }
  if (inst->op() == Nop) return nullptr;

  // copy propagation on inst source operands
  copyProp(inst);

  SSATmp* result = nullptr;

  if (m_enableSimplification) {
    result = m_simplifier.simplify(inst);
    if (result) {
      inst = result->inst();
      if (inst->producesReference(0)) {
        // This effectively prevents CSE from kicking in below, which
        // would replace the instruction with an IncRef.  That is
        // correct if the simplifier morphed the instruction, but it's
        // incorrect if the simplifier returned one of original
        // instruction sources.  We currently have no way to
        // distinguish the two cases, so we prevent CSE completely for
        // now.
        return result;
      }
    }
  }

  if (m_state.enableCse() && inst->canCSE()) {
    SSATmp* cseResult = m_state.cseLookup(inst, idoms);
    if (cseResult) {
      // Found a dominating instruction that can be used instead of inst
      FTRACE(1, "  {}cse found: {}\n",
             indent(), cseResult->inst()->toString());

      assert(!inst->consumesReferences());
      if (inst->producesReference(0)) {
        // Replace with an IncRef
        FTRACE(1, "  {}cse of refcount-producing instruction\n", indent());
        gen(IncRef, cseResult);
      }
      return cseResult;
    }
  }

  return result;
}
Example #4
0
SSATmp* TraceBuilder::optimizeWork(IRInstruction* inst,
                                   const folly::Optional<IdomVector>& idoms) {
  // Since some of these optimizations inspect tracked state, we don't
  // perform any of them on non-main traces.
  if (m_savedTraces.size() > 0) return nullptr;

  static DEBUG_ONLY __thread int instNest = 0;
  if (debug) ++instNest;
  SCOPE_EXIT { if (debug) --instNest; };
  DEBUG_ONLY auto indent = [&] { return std::string(instNest * 2, ' '); };

  FTRACE(1, "{}{}\n", indent(), inst->toString());

  // turn off ActRec optimization for instructions that will require a frame
  if (m_state.needsFPAnchor(inst)) {
    m_state.setHasFPAnchor();
    always_assert(m_state.fp() != nullptr);
    gen(InlineFPAnchor, m_state.fp());
    FTRACE(2, "Anchor for: {}\n", inst->toString());
  }

  // First pass of tracebuilder optimizations try to replace an
  // instruction based on tracked state before we do anything else.
  // May mutate the IRInstruction in place (and return nullptr) or
  // return an SSATmp*.
  if (SSATmp* preOpt = preOptimize(inst)) {
    FTRACE(1, "  {}preOptimize returned: {}\n",
           indent(), preOpt->inst()->toString());
    return preOpt;
  }
  if (inst->op() == Nop) return nullptr;

  // copy propagation on inst source operands
  copyProp(inst);

  SSATmp* result = nullptr;
  if (m_state.enableCse() && inst->canCSE()) {
    result = m_state.cseLookup(inst, idoms);
    if (result) {
      // Found a dominating instruction that can be used instead of inst
      FTRACE(1, "  {}cse found: {}\n",
             indent(), result->inst()->toString());

      // CheckType and AssertType are special. They're marked as both PRc and
      // CRc to placate our refcounting optimizations, for for the purposes of
      // CSE they're neither.
      if (inst->is(CheckType, AssertType)) {
        return result;
      }
      assert(!inst->consumesReferences());
      if (inst->producesReference()) {
        // Replace with an IncRef
        FTRACE(1, "  {}cse of refcount-producing instruction\n", indent());
        return gen(IncRef, result);
      } else {
        return result;
      }
    }
  }

  if (m_enableSimplification) {
    result = m_simplifier.simplify(inst);
    if (result) {
      // Found a simpler instruction that can be used instead of inst
      FTRACE(1, "  {}simplification returned: {}\n",
             indent(), result->inst()->toString());
      assert(inst->hasDst());
      return result;
    }
  }
  return nullptr;
}
Example #5
0
/*
 * Performs simplification and CSE on the input instruction. If the input
 * instruction has a dest, this will return an SSATmp that represents the same
 * value as dst(0) of the input instruction. If the input instruction has no
 * dest, this will return nullptr.
 *
 * The caller never needs to clone or append; all this has been done.
 */
SSATmp* IRBuilder::optimizeInst(IRInstruction* inst,
                                CloneFlag doClone,
                                Block* srcBlock,
                                const folly::Optional<IdomVector>& idoms) {
  static DEBUG_ONLY __thread int instNest = 0;
  if (debug) ++instNest;
  SCOPE_EXIT { if (debug) --instNest; };
  DEBUG_ONLY auto indent = [&] { return std::string(instNest * 2, ' '); };

  auto doCse = [&] (IRInstruction* cseInput) -> SSATmp* {
    if (m_state.enableCse() && cseInput->canCSE()) {
      SSATmp* cseResult = m_state.cseLookup(cseInput, srcBlock, idoms);
      if (cseResult) {
        // Found a dominating instruction that can be used instead of input
        FTRACE(1, "  {}cse found: {}\n",
               indent(), cseResult->inst()->toString());

        assert(!cseInput->consumesReferences());
        if (cseInput->producesReference(0)) {
          // Replace with an IncRef
          FTRACE(1, "  {}cse of refcount-producing instruction\n", indent());
          gen(IncRef, cseResult);
        }
        return cseResult;
      }
    }
    return nullptr;
  };

  auto cloneAndAppendOriginal = [&] () -> SSATmp* {
    if (inst->op() == Nop) return nullptr;
    if (auto cseResult = doCse(inst)) {
      return cseResult;
    }
    if (doClone == CloneFlag::Yes) {
      inst = m_unit.cloneInstruction(inst);
    }
    appendInstruction(inst);
    return inst->dst(0);
  };

  // Since some of these optimizations inspect tracked state, we don't
  // perform any of them on non-main traces.
  if (m_savedBlocks.size() > 0) return cloneAndAppendOriginal();

  // copy propagation on inst source operands
  copyProp(inst);

  // First pass of IRBuilder optimizations try to replace an
  // instruction based on tracked state before we do anything else.
  // May mutate the IRInstruction in place (and return nullptr) or
  // return an SSATmp*.
  if (SSATmp* preOpt = preOptimize(inst)) {
    FTRACE(1, "  {}preOptimize returned: {}\n",
           indent(), preOpt->inst()->toString());
    return preOpt;
  }
  if (inst->op() == Nop) return cloneAndAppendOriginal();

  if (!m_enableSimplification) {
    return cloneAndAppendOriginal();
  }

  auto simpResult = m_simplifier.simplify(inst, shouldConstrainGuards());

  // These are the possible outputs:
  //
  // ([], nullptr): no optimization possible. Use original inst.
  //
  // ([], non-nullptr): passing through a src. Don't CSE.
  //
  // ([X, ...], Y): throw away input instruction, append 'X, ...' (CSEing
  //                as we go), return Y.

  if (!simpResult.instrs.empty()) {
    // New instructions were generated. Append the new ones, filtering out Nops.
    for (auto* newInst : simpResult.instrs) {
      assert(!newInst->isTransient());
      if (newInst->op() == Nop) continue;

      auto cseResult = doCse(newInst);
      if (cseResult) {
        appendInstruction(m_unit.mov(newInst->dst(), cseResult,
                                     newInst->marker()));
      } else {
        appendInstruction(newInst);
      }
    }

    return simpResult.dst;
  }

  // No new instructions were generated. Either simplification didn't do
  // anything, or we're using some other instruction's dst instead of our own.

  if (simpResult.dst) {
    // We're using some other instruction's output. Don't append anything, and
    // don't do any CSE.
    assert(simpResult.dst->inst() != inst);
    return simpResult.dst;
  }

  // No simplification happened.
  return cloneAndAppendOriginal();
}