-
Notifications
You must be signed in to change notification settings - Fork 15
Open
Description
We are currently performing formal verification on HeteroCL, and we have discovered an undefined behavior introduced by the reuse_at
transformation. The input code is as follows:
func.func @blur_x(%A: memref<10x10xf32>, %B: memref<8x10xf32>)
{
%s = hcl.create_op_handle "s"
%li = hcl.create_loop_handle %s, "i"
%lj = hcl.create_loop_handle %s, "j"
affine.for %i = 0 to 8 {
affine.for %j = 0 to 10 {
%tmp = affine.load %A[%i, %j] : memref<10x10xf32>
%tmp1 = affine.load %A[%i+1, %j] : memref<10x10xf32>
%tmp2 = affine.load %A[%i+2, %j] : memref<10x10xf32>
%sum = arith.addf %tmp, %tmp1: f32
%sum1 = arith.addf %sum, %tmp2: f32
affine.store %sum1, %B[%i, %j] : memref<8x10xf32>
} { loop_name = "j" }
} { loop_name = "i", op_name = "s" }
%buf = hcl.reuse_at(%A: memref<10x10xf32>, %li) -> memref<3x10xf32>
return
}
After running hcl-opt -opt
, the output code is:
func.func @blur_x(%arg0: memref<10x10xf32>, %arg1: memref<8x10xf32>) {
%0 = memref.alloc() {name = "s_reuse_0"} : memref<3x10xf32>
affine.for %arg2 = 0 to 10 {
affine.for %arg3 = 0 to 10 {
%1 = affine.load %0[1, %arg3] : memref<3x10xf32>
affine.store %1, %0[0, %arg3] : memref<3x10xf32>
%2 = affine.load %0[2, %arg3] : memref<3x10xf32>
affine.store %2, %0[1, %arg3] : memref<3x10xf32>
%3 = affine.load %arg0[%arg2, %arg3] : memref<10x10xf32>
affine.store %3, %0[2, %arg3] : memref<3x10xf32>
} {spatial}
affine.if #set0(%arg2) {
affine.for %arg3 = 0 to 10 {
%1 = affine.load %0[0, %arg3] : memref<3x10xf32>
%2 = affine.load %0[1, %arg3] : memref<3x10xf32>
%3 = affine.load %0[2, %arg3] : memref<3x10xf32>
%4 = arith.addf %1, %2 : f32
%5 = arith.addf %4, %3 : f32
affine.store %5, %arg1[%arg2 - 2, %arg3] : memref<8x10xf32>
} {loop_name = "j"}
}
} {loop_name = "i", op_name = "s"}
return
}
The issue occurs when HeteroCL allocates a new memory block (%0 = memref.alloc() {name = "s_reuse_0"} : memref<3x10xf32>)
and reads from it without initializing it first (%1 = affine.load %0[1, %arg3] : memref<3x10xf32>
.
In MLIR, reading uninitialized memory is considered undefined behavior. The input code only has undefined behavior of reading from A and B when they are uninitialized, which implies that the reuse_at
transformation introduces new undefined behavior does not exist in the input code.
Metadata
Metadata
Assignees
Labels
No labels