brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · 5ac838c Raw
199 lines · cpp
1//===- ControlFlowToSCF.h - ControlFlow to SCF -------------*- C++ ------*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Define conversions from the ControlFlow dialect to the SCF dialect.10//11//===----------------------------------------------------------------------===//12 13#include "mlir/Conversion/ControlFlowToSCF/ControlFlowToSCF.h"14 15#include "mlir/Dialect/Arith/IR/Arith.h"16#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"17#include "mlir/Dialect/Func/IR/FuncOps.h"18#include "mlir/Dialect/SCF/IR/SCF.h"19#include "mlir/Dialect/UB/IR/UBOps.h"20#include "mlir/Pass/Pass.h"21#include "mlir/Transforms/CFGToSCF.h"22 23namespace mlir {24#define GEN_PASS_DEF_LIFTCONTROLFLOWTOSCFPASS25#include "mlir/Conversion/Passes.h.inc"26} // namespace mlir27 28using namespace mlir;29 30FailureOr<Operation *>31ControlFlowToSCFTransformation::createStructuredBranchRegionOp(32    OpBuilder &builder, Operation *controlFlowCondOp, TypeRange resultTypes,33    MutableArrayRef<Region> regions) {34  if (auto condBrOp = dyn_cast<cf::CondBranchOp>(controlFlowCondOp)) {35    assert(regions.size() == 2);36    auto ifOp = scf::IfOp::create(builder, controlFlowCondOp->getLoc(),37                                  resultTypes, condBrOp.getCondition());38    ifOp.getThenRegion().takeBody(regions[0]);39    ifOp.getElseRegion().takeBody(regions[1]);40    return ifOp.getOperation();41  }42 43  if (auto switchOp = dyn_cast<cf::SwitchOp>(controlFlowCondOp)) {44    // `getCFGSwitchValue` returns an i32 that we need to convert to index45    // fist.46    auto cast = arith::IndexCastUIOp::create(47        builder, controlFlowCondOp->getLoc(), builder.getIndexType(),48        switchOp.getFlag());49    SmallVector<int64_t> cases;50    if (auto caseValues = switchOp.getCaseValues())51      llvm::append_range(52          cases, llvm::map_range(*caseValues, [](const llvm::APInt &apInt) {53            return apInt.getZExtValue();54          }));55 56    assert(regions.size() == cases.size() + 1);57 58    auto indexSwitchOp =59        scf::IndexSwitchOp::create(builder, controlFlowCondOp->getLoc(),60                                   resultTypes, cast, cases, cases.size());61 62    indexSwitchOp.getDefaultRegion().takeBody(regions[0]);63    for (auto &&[targetRegion, sourceRegion] :64         llvm::zip(indexSwitchOp.getCaseRegions(), llvm::drop_begin(regions)))65      targetRegion.takeBody(sourceRegion);66 67    return indexSwitchOp.getOperation();68  }69 70  controlFlowCondOp->emitOpError(71      "Cannot convert unknown control flow op to structured control flow");72  return failure();73}74 75LogicalResult76ControlFlowToSCFTransformation::createStructuredBranchRegionTerminatorOp(77    Location loc, OpBuilder &builder, Operation *branchRegionOp,78    Operation *replacedControlFlowOp, ValueRange results) {79  scf::YieldOp::create(builder, loc, results);80  return success();81}82 83FailureOr<Operation *>84ControlFlowToSCFTransformation::createStructuredDoWhileLoopOp(85    OpBuilder &builder, Operation *replacedOp, ValueRange loopVariablesInit,86    Value condition, ValueRange loopVariablesNextIter, Region &&loopBody) {87  Location loc = replacedOp->getLoc();88  auto whileOp = scf::WhileOp::create(89      builder, loc, loopVariablesInit.getTypes(), loopVariablesInit);90 91  whileOp.getBefore().takeBody(loopBody);92 93  builder.setInsertionPointToEnd(&whileOp.getBefore().back());94  // `getCFGSwitchValue` returns a i32. We therefore need to truncate the95  // condition to i1 first. It is guaranteed to be either 0 or 1 already.96  scf::ConditionOp::create(97      builder, loc,98      arith::TruncIOp::create(builder, loc, builder.getI1Type(), condition),99      loopVariablesNextIter);100 101  Block *afterBlock = builder.createBlock(&whileOp.getAfter());102  afterBlock->addArguments(103      loopVariablesInit.getTypes(),104      SmallVector<Location>(loopVariablesInit.size(), loc));105  scf::YieldOp::create(builder, loc, afterBlock->getArguments());106 107  return whileOp.getOperation();108}109 110Value ControlFlowToSCFTransformation::getCFGSwitchValue(Location loc,111                                                        OpBuilder &builder,112                                                        unsigned int value) {113  return arith::ConstantOp::create(builder, loc,114                                   builder.getI32IntegerAttr(value));115}116 117void ControlFlowToSCFTransformation::createCFGSwitchOp(118    Location loc, OpBuilder &builder, Value flag,119    ArrayRef<unsigned int> caseValues, BlockRange caseDestinations,120    ArrayRef<ValueRange> caseArguments, Block *defaultDest,121    ValueRange defaultArgs) {122  cf::SwitchOp::create(builder, loc, flag, defaultDest, defaultArgs,123                       llvm::to_vector_of<int32_t>(caseValues),124                       caseDestinations, caseArguments);125}126 127Value ControlFlowToSCFTransformation::getUndefValue(Location loc,128                                                    OpBuilder &builder,129                                                    Type type) {130  return ub::PoisonOp::create(builder, loc, type, nullptr);131}132 133FailureOr<Operation *>134ControlFlowToSCFTransformation::createUnreachableTerminator(Location loc,135                                                            OpBuilder &builder,136                                                            Region &region) {137 138  // TODO: This should create a `ub.unreachable` op. Once such an operation139  //       exists to make the pass independent of the func dialect. For now just140  //       return poison values.141  Operation *parentOp = region.getParentOp();142  auto funcOp = dyn_cast<func::FuncOp>(parentOp);143  if (!funcOp)144    return emitError(loc, "Cannot create unreachable terminator for '")145           << parentOp->getName() << "'";146 147  return func::ReturnOp::create(148             builder, loc,149             llvm::map_to_vector(150                 funcOp.getResultTypes(),151                 [&](Type type) { return getUndefValue(loc, builder, type); }))152      .getOperation();153}154 155namespace {156 157struct LiftControlFlowToSCF158    : public impl::LiftControlFlowToSCFPassBase<LiftControlFlowToSCF> {159 160  using Base::Base;161 162  void runOnOperation() override {163    ControlFlowToSCFTransformation transformation;164 165    bool changed = false;166    Operation *op = getOperation();167    WalkResult result = op->walk([&](func::FuncOp funcOp) {168      if (funcOp.getBody().empty())169        return WalkResult::advance();170 171      auto &domInfo = funcOp != op ? getChildAnalysis<DominanceInfo>(funcOp)172                                   : getAnalysis<DominanceInfo>();173 174      auto visitor = [&](Operation *innerOp) -> WalkResult {175        for (Region &reg : innerOp->getRegions()) {176          FailureOr<bool> changedFunc =177              transformCFGToSCF(reg, transformation, domInfo);178          if (failed(changedFunc))179            return WalkResult::interrupt();180 181          changed |= *changedFunc;182        }183        return WalkResult::advance();184      };185 186      if (funcOp->walk<WalkOrder::PostOrder>(visitor).wasInterrupted())187        return WalkResult::interrupt();188 189      return WalkResult::advance();190    });191    if (result.wasInterrupted())192      return signalPassFailure();193 194    if (!changed)195      markAllAnalysesPreserved();196  }197};198} // namespace199