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 gpubranching - 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:
- declare separate package routes
- keep route implementations in the package
- let the Morph graph resolve which route is active
Do not centralize provider-specific lowering in core.
Next Steps
- LLVM Route Signatures - how route declarations describe host LLVM requirements
- Emit Walkthrough - how backend emitters consume route information