Exemple #1
0
def testBuildFuncOp():
  ctx = Context()
  with Location.unknown(ctx) as loc:
    m = builtin.ModuleOp()

    f32 = F32Type.get()
    tensor_type = RankedTensorType.get((2, 3, 4), f32)
    with InsertionPoint.at_block_begin(m.body):
      f = func.FuncOp(name="some_func",
                            type=FunctionType.get(
                                inputs=[tensor_type, tensor_type],
                                results=[tensor_type]),
                            visibility="nested")
      # CHECK: Name is: "some_func"
      print("Name is: ", f.name)

      # CHECK: Type is: (tensor<2x3x4xf32>, tensor<2x3x4xf32>) -> tensor<2x3x4xf32>
      print("Type is: ", f.type)

      # CHECK: Visibility is: "nested"
      print("Visibility is: ", f.visibility)

      try:
        entry_block = f.entry_block
      except IndexError as e:
        # CHECK: External function does not have a body
        print(e)

      with InsertionPoint(f.add_entry_block()):
        func.ReturnOp([f.entry_block.arguments[0]])
        pass

      try:
        f.add_entry_block()
      except IndexError as e:
        # CHECK: The function already has an entry block!
        print(e)

      # Try the callback builder and passing type as tuple.
      f = func.FuncOp(name="some_other_func",
                            type=([tensor_type, tensor_type], [tensor_type]),
                            visibility="nested",
                            body_builder=lambda f: func.ReturnOp(
                                [f.entry_block.arguments[0]]))

  # CHECK: module  {
  # CHECK:  func nested @some_func(%arg0: tensor<2x3x4xf32>, %arg1: tensor<2x3x4xf32>) -> tensor<2x3x4xf32> {
  # CHECK:   return %arg0 : tensor<2x3x4xf32>
  # CHECK:  }
  # CHECK:  func nested @some_other_func(%arg0: tensor<2x3x4xf32>, %arg1: tensor<2x3x4xf32>) -> tensor<2x3x4xf32> {
  # CHECK:   return %arg0 : tensor<2x3x4xf32>
  # CHECK:  }
  print(m)
Exemple #2
0
def testFunctionCalls():
    foo = func.FuncOp("foo", ([], []))
    foo.sym_visibility = StringAttr.get("private")
    bar = func.FuncOp("bar", ([], [IndexType.get()]))
    bar.sym_visibility = StringAttr.get("private")
    qux = func.FuncOp("qux", ([], [F32Type.get()]))
    qux.sym_visibility = StringAttr.get("private")

    with InsertionPoint(func.FuncOp("caller", ([], [])).add_entry_block()):
        func.CallOp(foo, [])
        func.CallOp([IndexType.get()], "bar", [])
        func.CallOp([F32Type.get()], FlatSymbolRefAttr.get("qux"), [])
        func.ReturnOp([])
Exemple #3
0
def testOpsAsArguments():
    index_type = IndexType.get()
    callee = func.FuncOp("callee", ([], [index_type, index_type]),
                         visibility="private")
    f = func.FuncOp("ops_as_arguments", ([], []))
    with InsertionPoint(f.add_entry_block()):
        lb = arith.ConstantOp.create_index(0)
        ub = arith.ConstantOp.create_index(42)
        step = arith.ConstantOp.create_index(2)
        iter_args = func.CallOp(callee, [])
        loop = scf.ForOp(lb, ub, step, iter_args)
        with InsertionPoint(loop.body):
            scf.YieldOp(loop.inner_iter_args)
        func.ReturnOp([])
Exemple #4
0
 def build(self, types: List[ir.Type]):
     """Builds the ir.Module.  The module has only the @main function,
 which will convert the input through the list of types and then back
 to the initial type.  The roundtrip type must be a dense tensor."""
     assert self._module is None, 'StressTest: must not call build() repeatedly'
     self._module = ir.Module.create()
     with ir.InsertionPoint(self._module.body):
         tp0 = types.pop(0)
         self._roundtripTp = tp0
         # TODO: assert dense? assert element type is recognised by the TypeConverter?
         types.append(tp0)
         funcTp = ir.FunctionType.get(inputs=[tp0], results=[tp0])
         funcOp = func.FuncOp(name='main', type=funcTp)
         funcOp.attributes['llvm.emit_c_interface'] = ir.UnitAttr.get()
         with ir.InsertionPoint(funcOp.add_entry_block()):
             arg0 = funcOp.entry_block.arguments[0]
             self._assertEqualsRoundtripTp(arg0.type)
             v = st.ConvertOp(types.pop(0), arg0)
             for tp in types:
                 w = st.ConvertOp(tp, v)
                 # Release intermediate tensors before they fall out of scope.
                 st.ReleaseOp(v.result)
                 v = w
             self._assertEqualsRoundtripTp(v.result.type)
             func.ReturnOp(v)
     return self
def testBlockCreation():
    with Context() as ctx, Location.unknown():
        module = Module.create()
        with InsertionPoint(module.body):
            f_type = FunctionType.get(
                [IntegerType.get_signless(32),
                 IntegerType.get_signless(16)], [])
            f_op = func.FuncOp("test", f_type)
            entry_block = f_op.add_entry_block()
            i32_arg, i16_arg = entry_block.arguments
            successor_block = entry_block.create_after(i32_arg.type)
            with InsertionPoint(successor_block) as successor_ip:
                assert successor_ip.block == successor_block
                func.ReturnOp([])
            middle_block = successor_block.create_before(i16_arg.type)

            with InsertionPoint(entry_block) as entry_ip:
                assert entry_ip.block == entry_block
                cf.BranchOp([i16_arg], dest=middle_block)

            with InsertionPoint(middle_block) as middle_ip:
                assert middle_ip.block == middle_block
                cf.BranchOp([i32_arg], dest=successor_block)
        print(module.operation)
        # Ensure region back references are coherent.
        assert entry_block.region == middle_block.region == successor_block.region
Exemple #6
0
def testTransferReadOp():
    module = Module.create()
    with InsertionPoint(module.body):
        vector_type = VectorType.get([2, 3], F32Type.get())
        memref_type = MemRefType.get([-1, -1], F32Type.get())
        index_type = IndexType.get()
        mask_type = VectorType.get(vector_type.shape,
                                   IntegerType.get_signless(1))
        identity_map = AffineMap.get_identity(vector_type.rank)
        identity_map_attr = AffineMapAttr.get(identity_map)
        f = func.FuncOp("transfer_read",
                        ([memref_type, index_type,
                          F32Type.get(), mask_type], []))
        with InsertionPoint(f.add_entry_block()):
            A, zero, padding, mask = f.arguments
            vector.TransferReadOp(vector_type,
                                  A, [zero, zero],
                                  identity_map_attr,
                                  padding,
                                  mask=mask)
            vector.TransferReadOp(vector_type, A, [zero, zero],
                                  identity_map_attr, padding)
            func.ReturnOp([])

    # CHECK: @transfer_read(%[[MEM:.*]]: memref<?x?xf32>, %[[IDX:.*]]: index,
    # CHECK: %[[PAD:.*]]: f32, %[[MASK:.*]]: vector<2x3xi1>)
    # CHECK: vector.transfer_read %[[MEM]][%[[IDX]], %[[IDX]]], %[[PAD]], %[[MASK]]
    # CHECK: vector.transfer_read %[[MEM]][%[[IDX]], %[[IDX]]], %[[PAD]]
    # CHECK-NOT: %[[MASK]]
    print(module)
Exemple #7
0
def testFuncArgumentAccess():
  with Context() as ctx, Location.unknown():
    ctx.allow_unregistered_dialects = True
    module = Module.create()
    f32 = F32Type.get()
    f64 = F64Type.get()
    with InsertionPoint(module.body):
      f = func.FuncOp("some_func", ([f32, f32], [f32, f32]))
      with InsertionPoint(f.add_entry_block()):
        func.ReturnOp(f.arguments)
      f.arg_attrs = ArrayAttr.get([
          DictAttr.get({
              "custom_dialect.foo": StringAttr.get("bar"),
              "custom_dialect.baz": UnitAttr.get()
          }),
          DictAttr.get({"custom_dialect.qux": ArrayAttr.get([])})
      ])
      f.result_attrs = ArrayAttr.get([
          DictAttr.get({"custom_dialect.res1": FloatAttr.get(f32, 42.0)}),
          DictAttr.get({"custom_dialect.res2": FloatAttr.get(f64, 256.0)})
      ])

      other = func.FuncOp("other_func", ([f32, f32], []))
      with InsertionPoint(other.add_entry_block()):
        func.ReturnOp([])
      other.arg_attrs = [
          DictAttr.get({"custom_dialect.foo": StringAttr.get("qux")}),
          DictAttr.get()
      ]

  # CHECK: [{custom_dialect.baz, custom_dialect.foo = "bar"}, {custom_dialect.qux = []}]
  print(f.arg_attrs)

  # CHECK: [{custom_dialect.res1 = 4.200000e+01 : f32}, {custom_dialect.res2 = 2.560000e+02 : f64}]
  print(f.result_attrs)

  # CHECK: func @some_func(
  # CHECK: %[[ARG0:.*]]: f32 {custom_dialect.baz, custom_dialect.foo = "bar"},
  # CHECK: %[[ARG1:.*]]: f32 {custom_dialect.qux = []}) ->
  # CHECK: f32 {custom_dialect.res1 = 4.200000e+01 : f32},
  # CHECK: f32 {custom_dialect.res2 = 2.560000e+02 : f64})
  # CHECK: return %[[ARG0]], %[[ARG1]] : f32, f32
  #
  # CHECK: func @other_func(
  # CHECK: %{{.*}}: f32 {custom_dialect.foo = "qux"},
  # CHECK: %{{.*}}: f32)
  print(module)
Exemple #8
0
def emit_timer_func() -> func.FuncOp:
    """Returns the declaration of nanoTime function. If nanoTime function is
    used, the `MLIR_RUNNER_UTILS` and `MLIR_C_RUNNER_UTILS` must be included.
    """
    i64_type = ir.IntegerType.get_signless(64)
    nanoTime = func.FuncOp("nanoTime", ([], [i64_type]), visibility="private")
    nanoTime.attributes["llvm.emit_c_interface"] = ir.UnitAttr.get()
    return nanoTime
def testFirstBlockCreation():
    with Context() as ctx, Location.unknown():
        module = Module.create()
        f32 = F32Type.get()
        with InsertionPoint(module.body):
            f = func.FuncOp("test", ([f32], []))
            entry_block = Block.create_at_start(f.operation.regions[0], [f32])
            with InsertionPoint(entry_block):
                func.ReturnOp([])

        print(module)
        assert module.operation.verify()
        assert f.body.blocks[0] == entry_block
Exemple #10
0
def emit_benchmark_wrapped_main_func(func, timer_func):
    """Takes a function and a timer function, both represented as FuncOp
    objects, and returns a new function. This new function wraps the call to
    the original function between calls to the timer_func and this wrapping
    in turn is executed inside a loop. The loop is executed
    len(func.type.results) times. This function can be used to create a
    "time measuring" variant of a function.
    """
    i64_type = ir.IntegerType.get_signless(64)
    memref_of_i64_type = ir.MemRefType.get([-1], i64_type)
    wrapped_func = func.FuncOp(
        # Same signature and an extra buffer of indices to save timings.
        "main",
        (func.arguments.types + [memref_of_i64_type], func.type.results),
        visibility="public"
    )
    wrapped_func.attributes["llvm.emit_c_interface"] = ir.UnitAttr.get()

    num_results = len(func.type.results)
    with ir.InsertionPoint(wrapped_func.add_entry_block()):
        timer_buffer = wrapped_func.arguments[-1]
        zero = arith.ConstantOp.create_index(0)
        n_iterations = memref.DimOp(ir.IndexType.get(), timer_buffer, zero)
        one = arith.ConstantOp.create_index(1)
        iter_args = list(wrapped_func.arguments[-num_results - 1:-1])
        loop = scf.ForOp(zero, n_iterations, one, iter_args)
        with ir.InsertionPoint(loop.body):
            start = func.CallOp(timer_func, [])
            call = func.CallOp(
                func,
                wrapped_func.arguments[:-num_results - 1] + loop.inner_iter_args
            )
            end = func.CallOp(timer_func, [])
            time_taken = arith.SubIOp(end, start)
            memref.StoreOp(time_taken, timer_buffer, [loop.induction_variable])
            scf.YieldOp(list(call.results))
        func.ReturnOp(loop)

    return wrapped_func