Skip to main content

Emit Walkthrough

Lowering is not the end of the story.

Many package features also need a backend emitter that turns a package-owned semantic family into concrete runtime or backend host operations.

The Graphics package has a strong real-world example.


Manifest Side

A backend emit route in feature.toml can look like this:

provider_id = "provider.core.host_llvm"
route_id = "host.llvm"
artifact_kind = "host.llvm_value"
required_extensions = ["llvm.runtime_import.v1"]
required_runtime_families = ["graphics"]
source = "backend/routes/host.llvm/Emit.cpp"
component_class = "graphics.cmd.draw.backend.hostllvm"

This says:

  • the route targets the host.llvm backend host via a concrete provider
  • the backend host must expose runtime import support
  • the graphics runtime family must exist
  • the emitter lives in a package-owned Emit.cpp

Real Emit Pattern

From morphs/Graphics/backend/routes/host.llvm/Emit.cpp:

bool emitStandardRuntimeRoute(MorphMorphBackendRouteContext *context,
const MorphMorphBackendOperationView *op,
std::string_view runtimeSymbol,
std::string *outError) {
BackendRouteApi api(*context);
std::vector<MorphMorphBackendValueHandle> arguments;
if (!materializeAllOperands(api, op, &arguments, outError)) {
return false;
}
MorphMorphBackendValueHandle result{};
const bool expectsResult = hasBindableResult(op);
if (!api.callRuntime(graphics_ids::kRuntimeFamily, runtimeSymbol, arguments,
expectsResult ? std::string_view(op->result_name)
: std::string_view{},
expectsResult ? &result : nullptr, outError)) {
return false;
}
return !expectsResult || bindIfNamed(api, op, result, outError);
}

This is a real package emitter:

  • materialize operands
  • call into the backend route API
  • route through a package-owned runtime family
  • bind the result if needed

A More Specialized Emit Case

The same file handles special behavior for material creation:

bool emitMaterialCreateRoute(MorphMorphBackendRouteContext *context,
const MorphMorphBackendOperationView *op,
std::string *outError) {
...
const std::string shaderName = rawShaderName != nullptr ? rawShaderName : "";
if (shaderName.empty()) {
if (outError != nullptr) {
*outError = "graphics.material.create received an empty shader name";
}
return false;
}

BackendRouteApi api(*context);
MorphMorphBackendValueHandle descriptor{};
if (!api.namedArtifactDescriptor("graphics", shaderName, &descriptor,
outError)) {
return false;
}
...
if (!api.callRuntime(graphics_ids::kRuntimeFamily,
graphics_ids::kRuntimeSymbolMaterialCreate, {descriptor},
expectsResult ? std::string_view(op->result_name)
: std::string_view{},
expectsResult ? &result : nullptr, outError)) {
return false;
}
...
}

Now the emitter is doing more than a raw runtime call:

  • reading operation operands
  • resolving a named artifact descriptor
  • calling a package runtime symbol with a descriptor payload

This is exactly the kind of advanced behavior that still belongs in package space.


One Emit File, Many Semantic Families

The same Graphics emitter dispatches over many semantic families:

extern "C" int morph_graphics_backend_hostllvm_emit(
MorphMorphBackendRouteContext *context,
const MorphMorphBackendOperationView *op, const char **out_error) {
...
const std::string_view semanticFamily =
op->semantic_family_id != nullptr ? op->semantic_family_id : "";
const RouteDef *route = findRouteDef(semanticFamily);
if (route == nullptr) {
morph::morph::exportBackendRouteFailure(
"graphics backend route received an unknown semantic family", out_error);
return 0;
}
...
}

This is still package-owned because the semantic families and route table belong to Graphics.


What Emit Means In Practice

For Morph authors, an emit file is where a backend route:

  • reads lowered operations
  • validates route-specific assumptions
  • materializes operands
  • calls backend host APIs
  • binds results
  • maps semantic families to runtime or backend behavior

It is not a generic dumping ground in core codegen.


Next Steps