In this PR, the users of BufferPlacement can configure

BufferAssginmentTypeConverter. These new configurations would give the user more

freedom in the process of converting function signature, and return and call

operation conversions.

These are the new features:

- Accepting callback functions for decomposing types (i.e. 1 to N type conversion such as unpacking tuple types).
- Defining ResultConversionKind for specifying whether a function result with a certain type should be appended to the function arguments list or should be kept as function result. (Usage: converter.setResultConversionKind<MemRefType>(AppendToArgumentList))
- Accepting callback functions for composing or decomposing values (i.e. N to 1 and 1 to N value conversion).

Input:

func @test(%arg0: tuple<tensor<2xf32>,i1>) -> (tuple<tensor<2xf32>,i1>){ return %arg0 : tuple<tensor<2xf32>,i1> }

Output with [converter.setResultConversionKind<MemRefType>(AppendToArgumentList)]:

func @test(%arg0: memref<2xf32>, %arg1: i1, %arg2: memref<2xf32>) -> i1 { %0 = "test.make_tuple"(%arg0, %arg1) : (memref<2xf32>, i1) -> tuple<memref<2xf32>, i1> %1 = "test.get_tuple_element"(%0) {index = 0 : i32} : (tuple<memref<2xf32>, i1>) -> memref<2xf32> %2 = "test.get_tuple_element"(%0) {index = 1 : i32} : (tuple<memref<2xf32>, i1>) -> i1 linalg.copy(%1, %arg2) : memref<2xf32>, memref<2xf32> return %2 : i1 }

Output with [converter.setResultConversionKind<MemRefType>(KeepAsFunctionResult)]:

func @test(%arg0: memref<2xf32>, %arg1: i1) -> (memref<2xf32>, i1) { %0 = "test.make_tuple"(%arg0, %arg1) : (memref<2xf32>, i1) -> tuple<memref<2xf32>, i1> %1 = "test.get_tuple_element"(%0) {index = 0 : i32} : (tuple<memref<2xf32>, i1>) -> memref<2xf32> %2 = "test.get_tuple_element"(%0) {index = 1 : i32} : (tuple<memref<2xf32>, i1>) -> i1 return %1, %2 : memref<2xf32>, i1 }