Bridging polyhedral analysis tools to the MLIR framework.
Polymer is a component of the Polygeist framework. Please read on to find how to install and use Polymer.
[bibtex]
Polymer is a essential component to the following two papers:
- Polygeist: Affine C in MLIR (IMPACT'21). This paper gives an overview of the whole Polygeist framework, in which Polymer does the polyhedral optimisation part of work.
- Phism: Polyhedral HLS in MLIR (LATTE'21). This paper demonstrates an interesting way to leverage Polymer for polyhedral HLS within the MLIR ecosystem.
- Polygeist: Raising C to Polyhedral MLIR (PACT'21). This is an updated version to the IMPACT'21 submission.
Polymer appears in the following talks:
- MLIR Open Dsign Meeting (11/02/2021) on Polygeist. [slides] [recording]
- LATTE '21 on Phism. [recording]
[legacy installation method] [submodule problem]
The recommended way of installing Polymer is to have it as a component of Polygeist. Please find the detailed instruction here.
You can also install Polymer as an individual, out-of-tree project.
Optimize MLIR code described in the Affine dialect by Pluto:
// File name: matmul.mlir
func @matmul() {
%A = memref.alloc() : memref<64x64xf32>
%B = memref.alloc() : memref<64x64xf32>
%C = memref.alloc() : memref<64x64xf32>
affine.for %i = 0 to 64 {
affine.for %j = 0 to 64 {
affine.for %k = 0 to 64 {
%0 = affine.load %A[%i, %k] : memref<64x64xf32>
%1 = affine.load %B[%k, %j] : memref<64x64xf32>
%2 = arith.mulf %0, %1 : f32
%3 = affine.load %C[%i, %j] : memref<64x64xf32>
%4 = arith.addf %2, %3 : f32
affine.store %4, %C[%i, %j] : memref<64x64xf32>
}
}
}
return
}
The following command will optimize this code piece.
# Go to the build/ directory.
./bin/polymer-opt -reg2mem -extract-scop-stmt -pluto-opt matmul.mlir
Output:
#map0 = affine_map<(d0) -> (d0 * 32)>
#map1 = affine_map<(d0) -> (d0 * 32 32)>
module {
func private @S0(%arg0: index, %arg1: index, %arg2: memref<64x64xf32>, %arg3: index, %arg4: memref<64x64xf32>, %arg5: memref<64x64xf32>) attributes {scop.stmt} {
%0 = affine.load %arg5[symbol(%arg0), symbol(%arg3)] : memref<64x64xf32>
%1 = affine.load %arg4[symbol(%arg3), symbol(%arg1)] : memref<64x64xf32>
%2 = arith.mulf %0, %1 : f32
%3 = affine.load %arg2[symbol(%arg0), symbol(%arg1)] : memref<64x64xf32>
%4 = arith.addf %2, %3 : f32
affine.store %4, %arg2[symbol(%arg0), symbol(%arg1)] : memref<64x64xf32>
return
}
func @matmul() {
%0 = memref.alloc() : memref<64x64xf32>
%1 = memref.alloc() : memref<64x64xf32>
%2 = memref.alloc() : memref<64x64xf32>
affine.for %arg0 = 0 to 2 {
affine.for %arg1 = 0 to 2 {
affine.for %arg2 = 0 to 2 {
affine.for %arg3 = #map0(%arg0) to #map1(%arg0) {
affine.for %arg4 = #map0(%arg2) to #map1(%arg2) {
affine.for %arg5 = #map0(%arg1) to #map1(%arg1) {
call @S0(%arg3, %arg5, %0, %arg4, %1, %2) : (index, index, memref<64x64xf32>, index, memref<64x64xf32>, memref<64x64xf32>) -> ()
}
}
}
}
}
}
return
}
}