## Motivation
Historically TVM ships a single monolithic `libtvm.so` that bundles both
the
runtime and the compiler/LLVM-heavy code paths. Deployment scenarios
that only
need the runtime end up paying the full compiler footprint (LLVM-static
dominates
the binary size), and the layout makes it awkward to install the project
under a
single Python package directory the way
`tvm_ffi`/`libinfo.load_lib_ctypes`
expects.
This PR splits the single shared library into two:
- `libtvm_runtime.so` — runtime-only symbols (loaded `RTLD_GLOBAL`).
- `libtvm_compiler.so` — compiler / LLVM / codegen, links
`libtvm_runtime.so`
publicly (loaded `RTLD_LOCAL`).
## Target restructure
- New CMake target `tvm_compiler` replaces the old `tvm` SHARED target.
- `tvm_compiler` depends on `tvm_runtime` via `target_link_libraries(...
PUBLIC tvm_runtime)`,
so anything that linked the old `tvm` now picks up the runtime
transitively.
- `tvm_libinfo_objs` (build-info TU) moved from `tvm_runtime` into
`tvm_compiler`
— it is compiler-side metadata and the runtime no longer needs it.
- All `target_link_libraries` / `target_compile_*` /
`set_target_properties` /
`tvm_ffi_add_apple_dsymutil` callsites have been rewired.
- The separate `libtvm_allvisible.so` target is **removed** (was only
consumed
by cpptests). Cpptests with private-symbol deps are deleted; remaining
cpptests now link directly against `libtvm_compiler.so` /
`libtvm_runtime.so`. `src/support/hexdump.cc` is folded into the header.
- `BUILD_DUMMY_LIBTVM` and the `BUILD_FOR_HEXAGON + USE_HEXAGON_GTEST`
cpp-test wiring are removed.
## Output and install layout
- All artifacts now go to `build/lib/` (was `build/`):
- `build/lib/libtvm_runtime.so`
- `build/lib/libtvm_compiler.so`
- Install layout is now `<package>/lib/` so
`tvm_ffi.libinfo.load_lib_ctypes`
with `package="tvm"` finds the libs in the wheel.
- CI Jenkins stash paths and `apps/hexagon_*` paths updated to the new
`build/lib/...` location.
## Python loader change
`python/tvm/base.py` now resolves the libs directly via a small
`package_lib_paths()` helper in `python/tvm/libinfo.py` (anchored on
`python/tvm/__file__`, returning the wheel `lib/`,
`<worktree>/build/lib`, and
`<worktree>/lib` candidates). Module-level `_LIB_RUNTIME`, `_LIB`, and
`_RUNTIME_ONLY` are set inline at import time:
- `libtvm_runtime.{so,dylib,dll}` loaded `RTLD_GLOBAL`.
- `libtvm_compiler.{so,dylib,dll}` loaded `RTLD_LOCAL`.
- `TVM_USE_RUNTIME_LIB` (parsed strictly: `1`/`true`/`yes`) selects
runtime-only at the loader level.
- When the compiler lib is absent, `_RUNTIME_ONLY` is set to True
automatically and `_LIB is _LIB_RUNTIME`.
## Non-obvious build-integration fixes
Three issues surfaced once both libs are loaded into the same process
and are
worth calling out:
1. **`fpA_intB_gemm` double-registration.** `fpA_intB_gemm_tvm` is an
OBJECT
library that registers a global `fastertransformer.gemm_fp16_int` at
static
init. Linking it into both `tvm_runtime` and `tvm_compiler` made the
registration run twice and trip the duplicate-registration check. Fix:
link
it (and the other runtime-only externals — `flash_attn`, NCCL, NVSHMEM,
RCCL) only into `tvm_runtime`. `tvm_compiler` picks them up via the
PUBLIC
`tvm_runtime` link.
2. **`-Wl,--no-as-needed` for minrpc.** `python/tvm/rpc/minrpc.py`
defaults
to `runtime="libtvm_runtime"` and passes `-Wl,--no-as-needed` so the
runtime static initializers actually run in the spawned minrpc binary
(without it, the linker drops the lib because no symbol is referenced
directly from the minrpc TU). minrpc does **not** link
`libtvm_compiler.so`.
3. **`testing.GetShape{Elem,Size}` moved to runtime.** Those two test
helpers
(the only `testing.*` symbols the minrpc test exercises) were registered
in
`src/support/ffi_testing.cc` (compiler-side). They are now registered in
`src/runtime/rpc/testing.cc` under `rpc.testing.GetShape{Elem,Size}` so
the minrpc server binary — runtime-only — can resolve them.
## Deprecations and breaking changes
- `BUILD_DUMMY_LIBTVM` is **removed** (option, libinfo entry, and CMake
wiring). Downstream consumers that built the dummy variant should link
`libtvm_runtime.so` directly.
- **Breaking change for downstream consumers** that read `libtvm.so` by
name:
there is no longer a `libtvm.so`. Replace with `libtvm_compiler.so`
(full)
or `libtvm_runtime.so` (runtime-only). The Vulkan device comment and a
few
test/CI comments have been updated accordingly.
- `libtvm_allvisible.so` is **removed**. Cpptests that depended on
private
out-of-line symbols have been deleted; the remaining cpp-test contract
is
documented as "public API or private header-only API only" (see
`tests/cpp/`).
- `tests/cpp-runtime/` (Hexagon + OpenCL backend tests) is **removed**
until
TVM moves to a plugin-mode backend architecture where each backend can
ship its own test harness with its own visibility scope.
## Tested
- `ninja` build: `build/lib/libtvm_runtime.so`,
`build/lib/libtvm_compiler.so`;
no `build/libtvm.so`, no `build/lib/libtvm_allvisible.so`.
`ldd build/lib/libtvm_compiler.so` links `libtvm_runtime.so`,
`libtvm_ffi.so`, `libfpA_intB_gemm.so`, `libflash_attn.so`.
- `ldd build/cpptest`: only `libtvm_compiler.so` + `libtvm_runtime.so` +
`libtvm_ffi.so` (no `libtvm_allvisible.so`).
- `./build/cpptest`: 144 / 144 tests pass across 29 suites.
- Smoke imports: full and `TVM_USE_RUNTIME_LIB=1` — both pass.
`TVM_USE_RUNTIME_LIB=0` correctly disables runtime-only mode (strict
parse).
- `tests/python/all-platform-minimal-test`: 75 passed, 77 skipped.
- `tests/python/runtime/`: 81 passed, 2 skipped (incl.
`test_rpc_return_remote_object` exercising the minrpc executable
end-to-end
via `rpc.testing.GetShape{Elem,Size}`).
- `tests/python/relax/test_vm_*.py`: 150 passed, 3 deselected
(`test_vm_multi_device.py` requires 3+ GPUs; host has 2 — env, not
regression),
2 xfailed.
- `tests/python/tirx-base/`: 273 passed, 2 skipped.
- `pre-commit` on edited files: green.
Closes#19443.
## Summary
Bump the minimum required LLVM version from 6.0 to 15.0, removing all
compatibility code for older LLVM versions.
- Update CMake minimum version checks in `FindLLVM.cmake` and
`LLVM.cmake`
- Remove ~90 dead `#if TVM_LLVM_VERSION` preprocessor branches across 15
source files
- Update documentation references in `from_source.rst` and
`config.cmake`
- 531 lines of dead code removed, no behavioral changes
All changes are strictly dead-code removal — no live code paths were
modified.
## Test plan
- [x] Build with LLVM 15 (`-DUSE_LLVM=ON`): passed
- [x] `test_target_codegen_llvm.py`: 40/40 passed
- [x] `pre-commit run --all-files`: passed
This PR phases out legacy target string format in favor of the json
style format that is more well formed. It also simplfies our overall
code in handling multiple formats.
* [FFI][REFACTOR] Cleanup namespace
This PR cleansup the namespace to ensure all ffi classes
are accessed through ffi:: namespace.
It will helps to cleanup the ffi package before isolation.
* fix hexagon
This PR fix TVM use with the latest LLVM version 21.
- At this time LLVM21 is available as a release candidate.
- Double checks for backward compatibility down to LLVM10
* cleanup relay c++
* [REFACTOR] Phase out relay c++ components
This PR phases out the relay C++ components and
simplifies the overall codegen runtime logic.
---------
Co-authored-by: Siyuan Feng <hzfengsy@sjtu.edu.cn>
This commit adds support for recognising when the SME architecture
feature is available based on the target string. A python user can
use `target.features.has_sme` to check availability.
Currently, target features are determined by a set of fixed checks on
the target string. This works well for checking support of a small
number of simple features, but it doesn't scale. Some problems include:
- There are many non-trivial conditions for which a feature may(not) be
available. It is easy to miss these with the current implementation.
- The inclusion of some features in a target string can imply other
features. For example, "+sve" implies "+neon". This currently isn't
taken into account.
- The tests in tests/cpp/target/parsers/aprofile_test.c suggest that
targets such as "llvm -mcpu=cortex-a+neon" and "llvm -mattr=+noneon"
are supported target strings. The features will be correctly parsed in
TVM, however, they are not valid in LLVM. Therefore, it's possible
that TVM and LLVM have different understanding of the features
available.
This commit uses the more robust LLVM target parser to determine support
for the features in TVM. It leverages previous infrastructure added to
TVM for obtaining a list of all supported features given an input
target, and uses this to check the existance of certain features we're
interested in. It should be trivial to grow this list over time. As a
result of this change, the problems mentioned above are solved.
In the current form, this commit drops support for target strings such
as "llvm -mcpu=cortex-a+neon" and "llvm -mattr=+noneon". A scan of the
codebase suggests this functionality is not in use (only in test cases).
Should we feel the need to support them, or have a smoother migration
for downstream users of TVM we can add a translator to the parser to
convert these into LLVM compatible targets.
Optimised fp16 conv2d matrix tiling for Arm(R) Neon(TM) instructions and exposed `+fullfp16` as a target feature for Arm(R) Cortex(R) A-Profile CPUs.
Also, a target test was added to `cpptest` for Arm(R) Cortex(R) A-Profile CPUs which checks that the `has_fp16_simd` flag is set exclusively when the user explicitly passes the `+fullfp16` or `+sve` attributes and a supporting architecture version at target creation.
* Expose SVE as a target feature for Arm(R) Cortex(R) A-Profile CPUs.
* Update the compute definition of `conv2d_spatial_pack_nhwc` to defer
to the LLVM backend for vectorization when compiling on an SVE enabled
target for data tensors with unit width and height since this has been
shown to be performant for wide vector architectures.
* Add a target test to `cpptest` for Arm(R) Cortex(R) A-Profile CPUs
which tests that the `has_sve` flag is set when the user explicitly
passes the `"+sve"` attribute on target creation. Because SVE is
optional on architecture versions 8.0 and later the test checks
whether it is optionally set.
* Make some pre-existing read only target properties constant.
The generated MLF header files for each module contain the struct definition to use as input and outputs to call the generated function. If we want to call this tvmgen_default_run, we need to allocate space (statically or dynamically) for the input and output tensors. This generates macros that define the size of each input and output in bytes, this allows us to reference this new macros to statically or dynamically allocate vectors to store the inputs and outputs of the tvmgen_default_run function.
Co-authored-by: Federico Peccia <peccia@fzi.de>
Co-authored-by: Christopher Sidebottom <chris.sidebottom@arm.com>
* [Target] Only append default keys if target doesn't have any yet
This allows target parsers to provide their own target keys. Without this
change, the default keys would always be appended, which may or may not
be desirable.
* Add "cpu" to ARM CPU keys
* Add "cpu" to the keys in the mprofile target parser
* Restore the mprofile cpptest, since the "cpu" key is back
* So the -device attribute is actually needed...
This implements an initial Target Parser which uses the same logic as
the CMSIS-NN compiler flags to update the features and keys of the `c`
and `llvm` `Target`s.
Refactoring of the CMSIS-NN logic will be in a separate patch.
* [Relay] Allow partial virtual device annotations.
Previously CompilationConfig::CanonicalVirtualDevice required
the argument virtual device to contain a device type. However
now that virtual devices may contain memory scopes that's
unnecessarily strict.
With this change it is possible to write virtual device
annotations with just memory scopes, and let PlanDevices
flow those constraints along with the usual device constraints.
* - Make sure CanonicalVirtualDevice reuses FullyUnconstrained
* [Relay] Allow Primitive function to carry virtual device annotations in PlanDevices
Previously Primitive=1 functions not analyzed and calls to such were completely
unconstrained. With this change at least any virtual device annotation on the function
are respected and accounted for in calls, even though the body is not analyzed.
This may help with piggy-backing on PlanDevices for doing memory scope analysis, since
it is now possible to express cross-scope functions on Primitive functions. However
I believe there are other issues to deal with in addition to this one.
* - comments
* - also canonicalize targets
When including virtual device annotations in test relay programs the
annotation will typically use a target which was used as an input to
the make_compilation_config helper, but due to various canonicalization
make not be pointer equal to the final structurally equal target which ends
up inside the constructed CompilationConfig. However VirtualDevices use
pointer equality when comparing their target field.
So make sure the notion of CanonicalVirtualDevice also accounts for canonical
targets.
* - update unit test to reflect the Ardreno example
* - trivial cleanup
* U3
Change-Id: Ibc088f19ad1dc9466fc368f8523baa30ee88b7d0
* addressed upstream comments
* Unit test added
Added unit test for InterfaceCNode::EmitConstantPool method
* [TIR.Constant] U1 usecase
Constants are now aggregated into one struct and initialized in default_lib0.c
file
Change-Id: I34d61f8139c8a92c06944fe990ba892a660476fd
Unit test fixed
Change-Id: I436e7b6d6b3064b3f8bbfbb048d4296b63a6b69c
* Refactored
Addressed:
* PoolInfo splitted to WorkspacePoolInfo and ConstantPoolInfo
* workspace_byte_alignment moved to ExecutorCodegenMetadata
* getModuleAlignment -> GetModuleAlignment
* GenerateInternalWorkspaceBuffers refactored
* reverted format change of src/tir/transforms/legalize_packed_calls.cc
* addressed comments for src/tir/usmp/analysis/extract_buffer_info.cc
* removed commented code from include/tvm/tir/usmp/utils.h
Change-Id: I7d1b32884b0e5992e2e00c7838c85e425d9c25fd
* more unit test fixes
Change-Id: I573a05fa1cb4037ae83691f7dff2c2724b1d7700
* More refactoring and unit test fixes
Added ConstantMemoryPools
Change-Id: If1e391c631575980564bca790ba33748c82d907f
* bugfix
Change-Id: Iacc7a9d734a505dfa0d8d32d23ea3f57e6de8582
* refactoring. added constant_alignment
added constant_alignment
unit tests updated
Change-Id: I378193cb9e675e352c61d96ff4e09655090053e1
* unit-test bugix
Change-Id: Ia4411d59c4a376c01326fed366cdb196a432899e
* unit test fix
Change-Id: Ia2077bdeb1d2c6c9827eeef90ab410ae31b8c4a4
* Added support for c++ runtime
* refactored
* renamed pools and consts
renamed pools and consts to workspace_pools and constant_pools
* addressed upstream comments
* addressed upstream comments-2
* addressed upstream comments-3
This commit adds end-to-end tests using the cascader
w/o striping. It needed few adjustments to the order
in which the arugments are provided to the entry point
function in AoT when both memory pools and devices
are present.
Change-Id: I37e04afd635add895e317586f628a62cae75f3fa
* Finish support for list-of-targets
This finishes the work started in https://github.com/apache/tvm/pull/11173 to support
'external codegen' targets in the N build-like API surfaces.
- It turns out it's ok if a build is given only a single 'external codegen' target, so remove that check
in CompilationConfig::Init. When Collage builds a 'candidate partition' it does so for a single target.
As far as Collage is concerned it does not care whether the target is regular (eg Target("cuda")), or
for a specific external codegen (eg Target("cutlass")), it just passes the target into the build.
- Add CompilationConfig::FindPrimitiveTargetForKind which I'll later need to retrieve
the external codegen Target instance corresponding to a "Compiler" attribute value.
- Target.update_target_host_consist was supporting three API styles:
- single target
- map from device type to target
- map from target to IRModule (for the ir_to_runtime API)
I replaced all those calls with a more specialized 'canonicalize' call:
- Target.canonicalize_target_and_host
- Target.canonicalize_multi_targets_and_host
- Target.canonicalize_target_map_and_host
In particular, all the tuning interfaces (task extraction, tuning, tuning records) all explicitly
*do not* support multiple targets since the underlying code just doesn't support that.
* - Lints
- Revert unintended changes
* - more lints
* - Fix model_library_format handling of target.
- Improve comments in compilation_config.h
* - Lints
- Update target/target_host params documentation
* - Fix micro library format tests
- Rev micro library format from 5 to 6
- Use Target.current() in a few places
* - eta contract comprehension
* - Woops, one more device: target map left
- Handle host already being in Target
* - lint
* - lint
* - Bug with append
- Take device type from target
* - Fix hexagon
* [Relay] Support 'external codegen targets'.
(Part of Collage, https://github.com/apache/tvm-rfcs/blob/main/rfcs/0062-collage.md)
This change prepares the VM and Relay target handling machinery to support
external codegen targets in addition to 'regular' targets. This allows us
to configure the build with Collage as follows:
```
host_target = tvm.target.Target("llvm")
targets = [tvm.target.Target("cuda", host_target),
tvm.target.Target("cutlass", host_target),
tvm.target.Target("cudnn", host_target)]
with tvm.transform.PassContext(...):
exe = tvm.relay.vm.compile(module, target=targets)
```
Four changes are required:
1. I introduce four new target kinds for the external codegens currently supported
by Collage. Others can be added as they are vetted for use by Collage. These
are given a device type matching the external codegen's assumption (ie just CUDA
currently), and given a target kind attribute "is_external_codegen" of True. The
latter is needed by Collage to signal the target kind name represents and external
codegen 'compiler' name. See the RFC for specifics.
2. I introduce the binary relation Target::IsExternalCodegenFor so that
external codegen targets can be related back to the 'underlying' targets
they are implicitly using in their codegen.
3. I rework the VMCompiler and BuildModule interfaces to accept an Array<Target> of
'raw targets' instead of a Map<Integer, Target>. This more general representation
is needed because we may now have multiple targets of the same device type
active simultaneously. I add new static methods on the Python Target to
convert to this form in a way that mimics check_and_update_host_consist.
4. I rework CompilationConfig to work from Array<Target> directly, to not depend
on the host_target argument (since dealt with on the Python side), and to
understand that if we have two targets for the same device type the non-external
codegen target takes precedence.
The change to CompilationConfig seems neutral with respect to the recent discussions
on compilation configuration representation and tvmc.
I made a few attempts to remove Target.check_and_update_host_const entirely in favor
of using CompilationConfig as the definitive target handling choke point but backed
out once they became too large.
* - Working on unit tests
* - Fix two Debug-only failures
* - Use Array<Target> in GraphExecutorCodegen/AOTExecutorCodegen ifaces instead
of CompilationConfig (don't want to bake it into any official APIs).
- Started unit tests.
* - Lints
* - Moar Lints
* - Fix some unit tests
* - Fix last unit test failures
* - whitespace
* - Address Eric's comments.
CI likely to fail due to stricter FindPrimitiveTargetOrFail but let's see.
* - Comment adjustments.
- Unit test for new Target members.
* [USMP] Adding support for U4 usecase
This commit adds support for placing I/O
tensors within the workspace buffer.
This is enabled using PassConfig option
tir.usmp.use_workspace_io. Once it is enabled,
it will remove the I/O tensors from the TIR
main PrimFunc and replace them with Allocate
nodes that is annotated to contain Input and
Output tensors.
The USMP will plan memory for them accordingly.
(i.e. it will re-use space used by them for
intermediaries depending on the liveness).
This will only be supported with C Interface API.
Thus, this commit produces two functions to the
metadata sources to obtain input and output structs
that points to location inside the workspace struct.
Change-Id: I4c7e750ead9a880ba900602c17f53a125f97dbf9
* fixup! [USMP] Adding support for U4 usecase
Change-Id: I78f03d36b12b4a5e8eae8d11701f51019489defc
* fixup! [USMP] Adding support for U4 usecase
Change-Id: I857f3d0ba7bc192d56d750c44b232998b2876e7a
This commit adds a MemoryPools argument for
the compilation flow according to RFC0029.
Moreover, it is used to provide support for
external pools from the application layer
that could be pinned for different memories
and/or be reused between multiple inferences
of a model.
This is a grab bag of fallout changes from switching the VM to use LoweTEPass
which can be easily split out of the main #9483 PR.
- AnnotateSpans can be used from C++ (though, unfortunately, it didn't help
me with debugging since spans are universally dropped in most passes).
- Can get a human readable dump of the VM's PackedFunc names and indexes for
debugging.
- If TVM_LOG_DEBUG defined then include types and ids of GlobalVars. I had
a lot of difficulty tracking down where duplicate GlobalVars for the same
name_hint were getting created and propagated.
- GetCallLoweredProps follows same API as GetDeviceCopy and GetOnDevice
where will return 'null' properties if call/expr is not of call_lowered
form. Mildly more convenient, though switching all the above to ICHECK
and push 'if (op == the relevant op)' into all use sites would also be just
fine.
- Misc VLOG improvements made while tracking down issues in #9483.
This PR exposes the workspace size as a macro
TVMGEN_DEFAULT_WORKSPACE_SIZE in tvmgen_default.h
(or TVMGEN_<MODEL_NAME>_WORKSPACE_SIZE in
tvmgen_<model_name>.h in the case that the model name is not default).
This functionality is useful for microTVM/AOT use cases
where it's useful to know the workspace size at compile time.
* [AOT][DeviceAPI] Connecting devices structure to relevant operators
This patch adds support for passing the device context via the unpacked API in AOT, generating an additional struct if necessary:
```c
/*!
* \brief Device context pointers for TVM module "default"
*/
struct tvmgen_default_devices {
void* npu;
};
```
Which is then added as an argument to the entry function:
```c
/*!
* \brief entrypoint function for TVM module "default"
* \param inputs Input tensors for the module
* \param outputs Output tensors for the module
* \param devices Device context pointers for the module
*/
int32_t tvmgen_default_run(
struct tvmgen_default_inputs* inputs,
struct tvmgen_default_outputs* outputs,
struct tvmgen_default_devices* devices
);
```
I've temporarily added the collection of external code generators to the TE compiler pending proper annotation of the eventual functions.
Co-authored-by: Grant Watson <grant.watson@arm.com>
* Correct "use_device_api" attribute name on Target
Co-authored-by: Grant Watson <grant.watson@arm.com>
(This is a bit of a grab bag in preparation for #9326
which I'm trying to minimize)
While switching the device planner to use SEScopes I had a lot
of trouble with Target's not matching up.
- If no explicit host target is given but the given
TargetMap has targets with hosts, try to use those
to establish the host_target.
- Make sure both the 'legacy' TargetMap representation
and the newer representation agree to pointer equality on
their targets.
- Make sure the Interpreter uses the target from CompilationConfig
since it's been normalized.
To debug the above:
- When in pretty printing with show_meta_data_ false give as much
detail on SEScopes, Targets and call attributes as possible.
That needed some rework in the relay_text_printer.cc.
- Ditto for critical 'target' attribute on PrimFuncs.
- Also added a Target::ToDebugString so I could see the
host fields along with everything else since a lot of problems
were caused by a mismatch of 'the same' Target with and without
a host. (Tried using that for the ReprPrinter but broken unit
tests.)
Note that the codebase assumes Targets are compared by ObjectPtrEquality,
yet CheckAndUpdateHostConsistency (I count 65 call sites) changes the targets.
Ultimately CompilationConfig or it's ultimate replacement should ensure we munge
targets only once at the 'main' entry points.
[Target] Adds SEScope (Storage/Execution Scope) for use as new unit of planning in 'device' planning
This is the first step in https://github.com/apache/tvm-rfcs/pull/38 to bring devices
and targets together when doing device planning. I've gone ahead and also included a
memory scope in this object since we will also need to propagate memory scopes across
Relay expressions once this basic preparation is in place. In the meantime that field will be
left as "".
Once device planning works in units of SEScopes it will be possible to directly read off
the device and target for any Relay sub-expression without the need for TargetMaps ort
the construction of default Targets.
SEScopes also support 'Join' and 'Default' operations needed when constraint solving in
the device planner. You can see those in use in my scratchpad branch:
https://github.com/mbs-octoml/mbs-tvm/tree/mbs-scopes
This PR also brings some duplicated and the ad-hoc 'default target' handling logic
together into a CompilationConfig class. (Again, see the scratchpad branch for how that
will end up being used). I've placed that next to SEScope since it's main purpose is to
a) establish the default SEScope for primitive ops
b) establish the SEScope for the 'host'
c) feed a definitive vector of Targets into device planning so it can resolve all
"on_device" and "device_copy" device references to their full SEScope form.
* Reworked to avoid global SEScopeCache.
Realized while working through unit tests in the sequel that it's reasonable
for folks to call build multiple times with distinct Target objects, in which
case the global cache would grow without bound.
So instead placed the cache in the CompilationConfig class. Since that class
now has everything the device planner needs to do its job, promoted it to
be an FFI-able Object, which is now in compilation_config.{h,cc}.
I think we can do much better with CompilationConfig, but for now keeping it
to the minimum I needed to prepare for device planning from all the executor
compilation codepaths.
Using the new name transformations added in #9088, the C interface API is now generated in C++ rather than in Python. This is intended to be a no-op for the actual users of this change and thus I've undone some of my overzealous sanitizing to match that expectation.
Follow up PRs will clean up any remaining name transformation inconsistencies.
Fixes#8792