#![allow(dead_code)]
use std::collections::BTreeMap;
use once_cell::sync::Lazy;
use crate::cli::Target;
#[derive(Debug, Clone)]
pub struct ApiInfo {
pub header: &'static str,
pub hip: Option<&'static str>,
pub sycl: Option<&'static str>,
pub rust: Option<&'static str>,
pub opencl: Option<&'static str>,
pub note: &'static str,
}
impl ApiInfo {
pub fn supports(&self, t: Target) -> bool {
self.mapping(t).is_some()
}
pub fn mapping(&self, t: Target) -> Option<&'static str> {
match t {
Target::Hip => self.hip,
Target::Sycl => self.sycl,
Target::Rust => self.rust,
Target::Opencl => self.opencl,
Target::All => None,
}
}
pub fn summarize(&self, t: Target) -> String {
if let Some(m) = self.mapping(t) {
format!("-> {t:?} = {m}")
} else {
format!("(no mapping for {t:?})")
}
}
}
pub type ApiMap = BTreeMap<&'static str, ApiInfo>;
pub fn database() -> &'static ApiMap {
&DATABASE
}
static DATABASE: Lazy<ApiMap> = Lazy::new(|| {
let mut m: ApiMap = BTreeMap::new();
insert(&mut m, "cudaMalloc", api("cuda_runtime.h",
Some("hipMalloc"), None, None, None,
"opencl: use clCreateBuffer + clEnqueueWriteBuffer"));
insert(&mut m, "cudaFree", api("cuda_runtime.h",
Some("hipFree"), None, None, None,
"opencl: use clReleaseMemObject"));
insert(&mut m, "cudaMemcpy", api("cuda_runtime.h",
Some("hipMemcpy"), None, None, None,
"opencl: clEnqueueCopyBuffer / clEnqueueReadBuffer"));
insert(&mut m, "cudaMemcpyAsync", api("cuda_runtime.h",
Some("hipMemcpyAsync"), None, None, None,
"async memcpy needs a queue on every backend"));
insert(&mut m, "cudaMemset", api("cuda_runtime.h",
Some("hipMemset"), None, None, None, ""));
insert(&mut m, "cudaMemcpyDeviceToHost", header_only("cuda_runtime.h"));
insert(&mut m, "cudaMemcpyHostToDevice", header_only("cuda_runtime.h"));
insert(&mut m, "cudaMemcpyDeviceToDevice", header_only("cuda_runtime.h"));
insert(&mut m, "cudaHostAlloc", api("cuda_runtime.h",
Some("hipHostMalloc"), None, None, None,
"opencl: use clCreateBuffer with CL_MEM_USE_HOST_PTR"));
insert(&mut m, "cudaMallocHost", api("cuda_runtime.h",
Some("hipHostMalloc"), None, None, None,
"opencl: clCreateBuffer with CL_MEM_ALLOC_HOST_PTR"));
insert(&mut m, "cudaMallocManaged", api("cuda_runtime.h",
Some("hipMallocManaged"), None, None, None,
"sycl: sycl::malloc_shared; opencl: clSVMAlloc (different signatures)"));
insert(&mut m, "cudaFreeHost", api("cuda_runtime.h",
Some("hipFreeHost"), None, None, None,
"sycl: sycl::free; opencl: clReleaseMemObject (different semantics)"));
insert(&mut m, "cudaMemcpyToSymbol", api("cuda_runtime.h",
Some("hipMemcpyToSymbol"), None, None, None,
"sycl/opencl: no symbol-table equivalent; use constant memory"));
insert(&mut m, "cudaMemcpyFromSymbol", api("cuda_runtime.h",
Some("hipMemcpyFromSymbol"), None, None, None,
"sycl/opencl: no symbol-table equivalent; use constant memory"));
insert(&mut m, "cudaStreamCreate", api("cuda_runtime.h",
Some("hipStreamCreate"), None, None, None,
"sycl/opencl: this maps to creating a queue / command queue"));
insert(&mut m, "cudaStreamDestroy", api("cuda_runtime.h",
Some("hipStreamDestroy"), None, None, None, ""));
insert(&mut m, "cudaStreamSynchronize", api("cuda_runtime.h",
Some("hipStreamSynchronize"), None, None, None,
"sycl: queue.wait(); opencl: clFinish / clWaitForEvents"));
insert(&mut m, "cudaEventCreate", api("cuda_runtime.h",
Some("hipEventCreate"), None, None, None, ""));
insert(&mut m, "cudaEventRecord", api("cuda_runtime.h",
Some("hipEventRecord"), None, None, None, ""));
insert(&mut m, "cudaEventSynchronize", api("cuda_runtime.h",
Some("hipEventSynchronize"), None, None, None, ""));
insert(&mut m, "cudaEventElapsedTime", api("cuda_runtime.h",
Some("hipEventElapsedTime"), None, None, None, ""));
insert(&mut m, "cudaEventDestroy", api("cuda_runtime.h",
Some("hipEventDestroy"), None, None, None, ""));
insert(&mut m, "cudaGetDeviceCount", api("cuda_runtime.h",
Some("hipGetDeviceCount"), None, None, None, ""));
insert(&mut m, "cudaGetDevice", api("cuda_runtime.h",
Some("hipGetDevice"), None, None, None, ""));
insert(&mut m, "cudaSetDevice", api("cuda_runtime.h",
Some("hipSetDevice"), None, None, None, ""));
insert(&mut m, "cudaGetLastError", api("cuda_runtime.h",
Some("hipGetLastError"), None, None, None, ""));
insert(&mut m, "cudaPeekAtLastError", api("cuda_runtime.h",
Some("hipPeekAtLastError"), None, None, None, ""));
insert(&mut m, "cudaGetErrorName", api("cuda_runtime.h",
Some("hipGetErrorName"), None, None, None, ""));
insert(&mut m, "cudaGetErrorString", api("cuda_runtime.h",
Some("hipGetErrorString"), None, None, None, ""));
insert(&mut m, "cudaDeviceSynchronize", api("cuda_runtime.h",
Some("hipDeviceSynchronize"), None, None, None,
"sycl: queue.wait_and_throw(); opencl: clFinish (require queue object)"));
insert(&mut m, "cudaDeviceReset", api("cuda_runtime.h",
Some("hipDeviceReset"), None, None, None,
"sycl/opencl: no direct equivalent; device reset is implicit"));
insert(&mut m, "cudaDeviceGetAttribute", api("cuda_runtime.h",
Some("hipDeviceGetAttribute"), None, None, None,
"sycl: device.get_info; opencl: clGetDeviceInfo (different signatures)"));
insert(&mut m, "cudaError_t", type_alias("cuda_runtime.h",
Some("hipError_t"), Some("sycl::errc"), Some("cust::CUresult"), Some("cl_int")));
insert(&mut m, "cudaStream_t", type_alias("cuda_runtime.h",
Some("hipStream_t"), Some("sycl::queue"), Some("cust::Stream"), Some("cl_command_queue")));
insert(&mut m, "cudaEvent_t", type_alias("cuda_runtime.h",
Some("hipEvent_t"), Some("sycl::event"), None, Some("cl_event")));
insert(&mut m, "dim3", type_alias("",
Some("dim3"), Some("sycl::range<3>"), Some("(u32, u32, u32)"), Some("[usize; 3]")));
for name in [
"__sinf", "__cosf", "__tanf", "__expf", "__logf", "__log2f", "__log10f",
"__powf", "__sqrtf", "__fdividef", "__fmaf_rn", "__fmul_rn",
"__fmadd_rd", "__float2int_rn", "__float2uint_rn",
] {
insert(&mut m, name, math_intrinsic(name));
}
m
});
fn insert(m: &mut ApiMap, name: &'static str, info: ApiInfo) {
m.insert(name, info);
}
const fn api(
header: &'static str,
hip: Option<&'static str>,
sycl: Option<&'static str>,
rust: Option<&'static str>,
opencl: Option<&'static str>,
note: &'static str,
) -> ApiInfo {
ApiInfo {
header,
hip,
sycl,
rust,
opencl,
note,
}
}
fn header_only(header: &'static str) -> ApiInfo {
ApiInfo {
header,
hip: Some("hipMemcpyKind"),
sycl: None,
rust: None,
opencl: None,
note: "enum constant; backend value is structural",
}
}
fn type_alias(
header: &'static str,
hip: Option<&'static str>,
sycl: Option<&'static str>,
rust: Option<&'static str>,
opencl: Option<&'static str>,
) -> ApiInfo {
ApiInfo {
header,
hip,
sycl,
rust,
opencl,
note: "type alias; no automatic code rewrite",
}
}
fn math_intrinsic(name: &'static str) -> ApiInfo {
ApiInfo {
header: "device_functions.h",
hip: Some(name),
sycl: Some("sycl::native::"),
rust: Some(name),
opencl: Some(name.trim_start_matches('_')),
note: "math intrinsic; mostly identical across HIP/OpenCL/Rust",
}
}
pub fn lookup(name: &str) -> Option<&'static ApiInfo> {
DATABASE.get(name)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cuda_malloc_maps_to_hip() {
let e = lookup("cudaMalloc").unwrap();
assert_eq!(e.hip, Some("hipMalloc"));
}
#[test]
fn cuda_event_t_maps_everywhere() {
let e = lookup("cudaEvent_t").unwrap();
assert!(e.hip.is_some());
assert!(e.sycl.is_some());
assert!(e.rust.is_none());
assert!(e.opencl.is_some());
}
#[test]
fn unknown_apis_return_none() {
assert!(lookup("cudaDefinitelyNotARealApi").is_none());
}
#[test]
fn cuda_device_synchronize_maps_to_hip() {
let e = lookup("cudaDeviceSynchronize").unwrap();
assert_eq!(e.hip, Some("hipDeviceSynchronize"));
assert!(e.sycl.is_none(), "SYCL requires queue object — semantic");
assert!(e.opencl.is_none(), "OpenCL requires command queue — semantic");
}
#[test]
fn cuda_malloc_managed_maps_to_hip() {
let e = lookup("cudaMallocManaged").unwrap();
assert_eq!(e.hip, Some("hipMallocManaged"));
}
#[test]
fn cuda_free_host_maps_to_hip() {
let e = lookup("cudaFreeHost").unwrap();
assert_eq!(e.hip, Some("hipFreeHost"));
}
#[test]
fn cuda_memcpy_to_from_symbol_maps_to_hip() {
let to = lookup("cudaMemcpyToSymbol").unwrap();
assert_eq!(to.hip, Some("hipMemcpyToSymbol"));
let from = lookup("cudaMemcpyFromSymbol").unwrap();
assert_eq!(from.hip, Some("hipMemcpyFromSymbol"));
}
#[test]
fn cuda_device_reset_and_attribute_map_to_hip() {
let reset = lookup("cudaDeviceReset").unwrap();
assert_eq!(reset.hip, Some("hipDeviceReset"));
let attr = lookup("cudaDeviceGetAttribute").unwrap();
assert_eq!(attr.hip, Some("hipDeviceGetAttribute"));
}
}