Skip to main content

Platform-Specific Lowering

A package feature can lower differently depending on the route or provider.

This is one of the main reasons Morph uses explicit route metadata instead of a single hardcoded lowering path.


A Real Example: Tensor Add

The Tensor package already lowers tensor.add differently for host LLVM and GPU Vulkan routes.

Manifest side:

[tensor.add.route.hostllvm]
provider_id = "provider.core.host_llvm"
route_id = "host.llvm"
artifact_kind = "host.nir_value"
required_extensions = []
required_runtime_families = []
description = "Lowers tensor.add into Morph-owned host NIR."
source = "Tensor/features/Add/routes/HostLLVM.cpp"
component_class = "tensor.add.route.hostllvm"

[tensor.add.route.gpuvulkan]
provider_id = "provider.gpu.vulkan"
route_id = "gpu.vulkan"
artifact_kind = "host.nir_value"
required_extensions = []
required_runtime_families = []
description = "Lowers tensor.add into Morph-owned gpu.vulkan host NIR."
source = "Tensor/features/Add/routes/GpuVulkan.cpp"
component_class = "tensor.add.route.gpuvulkan"

Host Route Implementation

class TensorAddHostRoute final : public HostRouteFeature {
public:
bool lower(LoweringContext &ctx, const morph::morph::FeatureFact &fact,
nir::Value **outValue, std::string *outError) override {
return tensor_surface::lowerTensorBinaryFeatureFact(ctx, fact, false, outValue,
outError);
}
};

MORPHLANG_MORPH_DEFINE_HOST_ROUTE_FACTORY(tensor_add_route_hostllvm,
TensorAddHostRoute)

GPU Route Implementation

class TensorAddGpuVulkanRoute final : public HostRouteFeature {
public:
bool lower(LoweringContext &ctx, const morph::morph::FeatureFact &fact,
nir::Value **outValue, std::string *outError) override {
return tensor_surface::lowerTensorBinaryFeatureFact(ctx, fact, true, outValue,
outError);
}
};

MORPHLANG_MORPH_DEFINE_HOST_ROUTE_FACTORY(tensor_add_route_gpuvulkan,
TensorAddGpuVulkanRoute)

What Changes Between The Two?

The feature owner stays the same.

What changes is the route-specific implementation choice:

  • host route passes false
  • GPU route passes true

That route selection is explicit in package metadata and explicit in package-owned code.


Why This Is Better Than Core Branching

The wrong design would be:

  • one big core lowerer
  • internal if host / if gpu branching
  • provider assumptions hidden in compiler core code

The correct Morph design is:

  • one semantic feature owner
  • multiple route declarations
  • multiple route implementations
  • explicit provider IDs

Design Rule

If a feature lowers differently per provider or platform:

  1. declare separate package routes
  2. keep route implementations in the package
  3. let the Morph graph resolve which route is active

Do not centralize provider-specific lowering in core.


Next Steps