Hi folks,
I am new to modular and looking at some demos/documentsions on MAX compiler.
Ideally, I want to define an op that can be “overrided” with different implementations on different target.
In the documented example, the target switching is done inside if/else target check inside the node definition,
@compiler.register("vector_addition")
struct VectorAddition:
@staticmethod
fn execute[
target: StaticString,
](
output: OutputTensor[rank=1],
lhs: InputTensor[dtype = output.dtype, rank = output.rank],
rhs: InputTensor[dtype = output.dtype, rank = output.rank],
ctx: DeviceContextPtr,
) raises:
@parameter
if target == "cpu":
_vector_addition_cpu(output, lhs, rhs, ctx)
elif target == "gpu":
_vector_addition_gpu(output, lhs, rhs, ctx)
else:
While this works in general, there might be a serious issue with scalarization:
Assume I wrote the original “general purpose op”, and my collaborators target authors want to provide “more advanced target-specific op” . Now the target authors will have to go into my node definition and modify the code there.
Ideally, they should be able to register their own version without modifying the initial node definition I wrote. Is there a way to register multiple versions of a custom node, each for a different target in different struct (and files)?
e.g., something like this
@compiler.register("mo.matmul")
struct MatmulReference:
@staticmethod
fn executetarget: StaticString:
# Standard nested loops or simple SIMD code
...
@compiler.register("mo.matmul")
struct MatmulCUDA:
@staticmethod
fn executetarget: StaticString:
# Hand-written PTX or calls to cuBLAS
Thank you very much.
Ye