Can not create function declaration while lowering

Hi,

I’m trying to lower ToyDialect in the tutorial to GPUDialect.

To use the mlir-cuda-ruuner, I need to declare a function mcuMemHostRegisterFloat, and call it while calling toy.constant.

Here is ConstantOpLowering in my lowerToGPU.cpp (it’s basically ConstantOpLowering in LowerToAffineLoops.cpp, I simply add rewriter.create<FuncOp> in the end)

class ConstantOpLowering : public ConversionPattern {
public:
  explicit ConstantOpLowering(MLIRContext *context)
      : ConversionPattern(toy::ConstantOp::getOperationName(), 1, context) {}

  LogicalResult
  matchAndRewrite(Operation *op, ArrayRef<Value> operands,
                  ConversionPatternRewriter &rewriter) const override {
    auto cop = cast<toy::ConstantOp>(op);
    DenseElementsAttr constantValue = cop.value();
    Location loc = cop.getLoc();

    ModuleOp parentModule = cop.getParentOfType<ModuleOp>();
    
    auto tensorType = cop.getType().cast<TensorType>();
    auto memRefType = convertTensorToMemRef(tensorType);
    auto alloc = insertAllocAndDealloc(memRefType, loc, rewriter);
    
    auto valueShape = memRefType.getShape();
    SmallVector<Value, 8> constantIndices;

    if (!valueShape.empty()) {
      for (auto i : llvm::seq<int64_t>(
              0, *std::max_element(valueShape.begin(), valueShape.end())))
       constantIndices.push_back(rewriter.create<ConstantIndexOp>(loc, i));
    } else {
      // This is the case of a tensor of rank 0.
      constantIndices.push_back(rewriter.create<ConstantIndexOp>(loc, 0));
    }

    SmallVector<Value, 2> indices;
    auto valueIt = constantValue.getValues<FloatAttr>().begin();
    std::function<void(uint64_t)> storeElements = [&](uint64_t dimension) {
      if (dimension == valueShape.size()) {
        rewriter.create<StoreOp>(
            loc, rewriter.create<ConstantOp>(loc, *valueIt++), alloc,
            llvm::makeArrayRef(indices));
        return;
      }

      for (uint64_t i = 0, e = valueShape[dimension]; i != e; ++i) {
        indices.push_back(constantIndices[i]);
        storeElements(dimension + 1);
        indices.pop_back();
      }
    };

    // Start the element storing recursion from the first dimension.
    storeElements(/*dimension=*/0);

    SmallVector<Type, 1> Input, Output;
    PatternRewriter::InsertionGuard insertGuard(rewriter);
    rewriter.setInsertionPointToStart(parentModule.getBody());
    auto registerFunc = rewriter.create<FuncOp>(parentModule.getLoc(), "mcuMemHostRegisterFloat", FunctionType::get(Input, Output, parentModule.getContext()));

    rewriter.replaceOp(op, alloc);
    return success();
  }
};

But I always get error: failed to legalize operation 'toy.constant' that was explicitly marked illegal while running. And if I remove

PatternRewriter::InsertionGuard insertGuard(rewriter);
rewriter.setInsertionPointToStart(parentModule.getBody());
auto registerFunc = rewriter.create<FuncOp>(parentModule.getLoc(), "mcuMemHostRegisterFloat", FunctionType::get(Input, Output, parentModule.getContext()));

it can run correctly.

So I’m really confused. Why a simple rewriter.create<FuncOp> makes different? How can I deal with that?

What’s your ConversionTarget? My guess is that the FuncOp you have created is determined to be not legal so the conversion framework does not apply your pattern (well technically backtracks the application) and therefore fails to legalize the const op.

-debug-only=dialect-conversion is a good way to debug what’s going on in the conversion framework. See Debugging - MLIR for more debugging tips and Dialect Conversion - MLIR for more about the conversion framework.

Thx :sweat_smile: …I thought FuncOp is just in StandardOpsDialect, so I did not add it as LegalOp. Now it works!

A dialect being “Standard” doesn’t mean it’s always desirable to use it so it has no effect on the conversion target. We are also moving towards splitting and removing this dialect to avoid such confusion in the future.