Affine.load op index must be a dimension or symbol identifier

my mlir looks like code below, where the type of %2, %4, %6, %8 are index, and when i run the compiler it hint the error that ’ affine.load op index must be a dimension or symbol identifier’ , could it convert the index type to the right type of affine.load indices?

%9 = affine.load %arg0[%2, %4, %6, %8] : memref<4x32x16x32xf32>

by the way, the index %2 comes from arith add and muli

                  %c2_index = arith.constant 2 : index                                                                                                                                                 
                    %1 = arith.muli %arg5, %c2_index : index                                                                                                                                             
                    %2 = arith.addi %1, %arg1 : index                 

You can read about dimensions and symbols here 'affine' Dialect - MLIR. In particular, the results of arithmetic dialect operations are not necessarily valid as operands for affine memory operations. They may be valid if they are placed at the top of an operation with the AffineScope trait, such as FuncOp. Your example does not provide sufficient context to see if it is the case.

Thanks @ftynse, my mlir semantic should like this,

%1 = affine.load %arg0[%arg1 + %arg5 * 2] : memref<32xf32>

where the %arg0, %arg1,%arg5 are both produced by affine.for, but in my project, the mlir should have the same semantic like this but there should have no ‘+’ , ‘*’ , while ‘+’, ‘*’ are replaced by arith.addi and arith.muli, so the ir looks like as follows:

%c2_index = arith.constant 2 : index
%1 = arith.muli %arg5, %c2_index : index
%2 = arith.addi %1, %arg1 : index
%9 = affine.load %arg0[%2]: memref<32xf32>

so the type of %2 is index and is invalid for affine.load, but i indeed want to use %2 for the input of affine.load. so I wonder that if there is any method to convert the index type to legal type of affine.load.

Except that it is not exactly the same semantics to have arith.addi instead of affine.apply (as suggested by @Mogball in your other post) or using the affine map directly in the affine.load, because of the different affine value categorization which is a part of the Affine dialect’s semantics. So your requirements are contradictory and you must reconsider one of them: either don’t use arith to compute indices for affine.load or don’t use affine.load (you can use memref.load).

You clearly misunderstand the affine value categorization. This has nothing to do with types. index is the expected type for affine loads. There is no need to convert it. It you had been using the wrong type, the error would have said exactly that. It does not. You may be confused by the wording “index must be a dimension or symbol identifier” in which the word “index” refers to the subscript operand of the load operation, not its type.

As suggested by others, please use affine.apply instead of “lower-level” arith dialect ops for subscript computations of affine load/stores. (You can perform add, mul, div, and rem using affine.apply’s. They’ll eventually be lowered to these arith dialect ops during the -lower-affine conversion.)

@ftynse
I ran into the same problem. But I wrote a Pass to convert all arith.add/mul/sub to AffineExpr. Now I’m not sure on how to use AffineMap. For example:

If I want to create this load op:

%3 = affine.load %arg0[0, %arg4, %arg1 + %arg2, %arg1 + %arg3] : memref<1x3x256x256xf32>

0 can be generated by getAffineConstantExpr and %arg1 + %arg2 can be got through getAffineDimExpr(0) + getAffineDimExpr(1).(operands are [%arg1, %arg2, %arg3, %arg4])

I don’t really understand how to create AffineMap. In c++ API:

mlir::AffineMap::get(/*dim*/ 4, /*symbol*/ 4, /*AffineExprs*/exprs, /*contex*/ctx)

For the affine.load example above, is this AffineMap created in the right way and what does the Symbol Count in AffineMap refer to?


Here is another simple example:

operands are [%arg3, %arg6, %arg7, %arg8]

%4 = affine.load %arg1[%arg3, %arg6, %arg7, %arg8] : memref<16x3x3x3xf32>

When building this op, I use:

exprs.push_back(b.getAffineDimExpr(0));
exprs.push_back(b.getAffineDimExpr(1));
exprs.push_back(b.getAffineDimExpr(2));
exprs.push_back(b.getAffineDimExpr(3));
auto map = mlir::AffineMap::get(/*dim*/ 4, /*symbol*/ 4, /*AffineExprs*/exprs,  /*contex*/ctx)

But map.getNumInputs() is 8. My understanding is that it should be 4.

Check this documentation: 'affine' Dialect - MLIR (also linked above).

But map.getNumInputs() is 8. My understanding is that it should be 4.

The code you posted requests 4 dimensions and 4 symbols, 4+4=8 inputs.