Why we should clean build result for IfOp's condition #167
zzzDavid
started this conversation in
Show and tell
Replies: 2 comments
-
So we need to add an "ast cleaner" to remove the previous build result and build the condition again at the current scope. def build_if_op(self, op: ast.IfOp, ip):
"""Build IfOp"""
# build condition
# clear condition build result from previous build
self.cleaner.visit(op.cond)
self.build_visitor(op.cond, ip)
has_else = op.else_branch_valid
if_op = scf_d.IfOp(op.cond.result, hasElse=has_else, results_=[], ip=ip)
# build then body
ip = InsertionPoint(if_op.then_block)
for body_op in op.body:
self.build_visitor(body_op, ip)
scf_d.YieldOp([], ip=ip)
# build else body
if has_else:
ip = InsertionPoint(if_op.else_block)
for body_op in op.else_body:
self.build_visitor(body_op, ip)
scf_d.YieldOp([], ip=ip)
op.ir_op = i |
Beta Was this translation helpful? Give feedback.
0 replies
-
With the condition being freshly built at every module {
func.func @top() -> memref<1xi32> attributes {bit, itypes = "", otypes = "u"} {
%c0 = arith.constant 0 : index
%0 = memref.alloc() {name = "res"} : memref<1xi32>
%c0_i32 = arith.constant 0 : i32
affine.store %c0_i32, %0[%c0] {to = "res", unsigned} : memref<1xi32>
%1 = memref.alloc() {name = "xy"} : memref<1x!hcl.struct<i8, i8>>
%c52_i8 = arith.constant {unsigned} 52 : i8
%c18_i8 = arith.constant {unsigned} 18 : i8
%2 = hcl.struct_construct(%c52_i8, %c18_i8) : i8, i8 -> <i8, i8>
affine.store %2, %1[%c0] {to = "xy"} : memref<1x!hcl.struct<i8, i8>>
%3 = affine.load %1[0] {from = "xy"} : memref<1x!hcl.struct<i8, i8>>
%4 = hcl.struct_get %3[0] : <i8, i8> -> i8
%c1_i32 = arith.constant 1 : i32
%5 = arith.extui %4 : i8 to i32
%6 = arith.cmpi eq, %5, %c1_i32 : i32
scf.if %6 {
affine.store %c1_i32, %0[0] {to = "res", unsigned} : memref<1xi32>
} else {
%12 = affine.load %1[0] {from = "xy"} : memref<1x!hcl.struct<i8, i8>>
%13 = hcl.struct_get %12[1] : <i8, i8> -> i8
%c2_i32 = arith.constant 2 : i32
%14 = arith.extui %13 : i8 to i32
%15 = arith.cmpi eq, %14, %c2_i32 : i32
scf.if %15 {
affine.store %c2_i32, %0[0] {to = "res", unsigned} : memref<1xi32>
}
}
%7 = affine.load %1[0] {from = "xy"} : memref<1x!hcl.struct<i8, i8>>
%8 = hcl.struct_get %7[0] : <i8, i8> -> i8
%c0_0 = arith.constant {unsigned} 0 : index
%9 = hcl.get_bit(%8 : i8, %c0_0) -> i1
%10 = arith.extui %9 : i1 to i32
%11 = arith.cmpi eq, %10, %c1_i32 : i32
scf.if %11 {
%c8_i32 = arith.constant 8 : i32
affine.store %c8_i32, %0[0] {to = "res", unsigned} : memref<1xi32>
} else {
%12 = affine.load %1[0] {from = "xy"} : memref<1x!hcl.struct<i8, i8>>
%13 = hcl.struct_get %12[1] : <i8, i8> -> i8
%c1 = arith.constant {unsigned} 1 : index
%14 = hcl.get_bit(%13 : i8, %c1) -> i1
%15 = arith.extui %14 : i1 to i32
%16 = arith.cmpi eq, %15, %c1_i32 : i32
scf.if %16 {
%c9_i32 = arith.constant 9 : i32
affine.store %c9_i32, %0[0] {to = "res", unsigned} : memref<1xi32>
}
}
return %0 : memref<1xi32>
}
} Note that there is a new |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
This thread shows why we should clean the condition's building result for IfOp. This discussion is relevant to the frontend implementation with AST, where we build a HeteroCL AST during create_schedule, and built MLIR IR in a second pass with IRBuilder.
How do we know the MLIR operation is built for an AST node in the second pass? Each AST node (Operation, Expr) has these two members:
.result
,.ir_op
. When an MLIR operation is built for that node, their_op
is set to the MLIR operation object, and.result
is set to the result of the MLIR operation, which is anOpResult
object. So we can check whether.ir_op
is None for any AST node to determine if its MLIR operation has been built, and access theOpResult
object with.result
.I want to show that we should clean the previous build result of if operation's condition expression because we may run into dominance issue if we use previous build results. Here is an example:
HeteroCL Code
IR that didn't pass MLIR verifier
Full IR
The important bit:
Note that because
%18
is defined in the firstscf.if
's body scope:%18 = "hcl.struct_get"(%8) {index = 1 : i64} : (!hcl.struct<i8, i8>) -> i8
The use of its result is not dominated by its definition:
%19 = "hcl.get_bit"(%18, %18) : (i8, index)
This is caused by the build result of this condition
with hcl.elif_(y == 2)
being reused when this conditionwith hcl.elif_(y[1] == 1):
is built.Beta Was this translation helpful? Give feedback.
All reactions