hexagon: Implement __clear_cache using inline assembly

Implement `__clear_cache` for Hexagon targets in Rust. Hexagon has
separate instruction and data caches, so this flushes dirty data cache
lines with `dccleaninva`, invalidates stale instruction cache lines
with `icinva`, then issues an `isync` barrier.

Based on the compiler-rt implementation from
llvm/llvm-project#188411.
This commit is contained in:
Brian Cain
2026-04-07 16:15:04 -07:00
committed by Trevor Gross
parent a6de51188b
commit a4fe265df0
@@ -1,5 +1,49 @@
use core::arch::global_asm;
// Hexagon L1 cache line size in bytes (Hexagon PRM sections 5.10.3-5.10.4).
const CACHE_LINE_SIZE: usize = 32;
intrinsics! {
pub unsafe extern "C" fn __clear_cache(start: *mut u8, end: *mut u8) {
// Hexagon has separate instruction and data caches.
let mask = !(CACHE_LINE_SIZE - 1);
let start_line = start.addr() & mask;
let end_addr = end.addr();
// Clean and invalidate data cache to push new code to memory and
// invalidate stale lines in the L2 cache.
let mut addr = start_line;
while addr < end_addr {
unsafe {
core::arch::asm!(
"dccleaninva({addr})",
addr = in(reg) addr,
options(nostack, preserves_flags),
);
}
addr += CACHE_LINE_SIZE;
}
// Invalidate instruction cache so it re-fetches from memory.
addr = start_line;
while addr < end_addr {
unsafe {
core::arch::asm!(
"icinva({addr})",
addr = in(reg) addr,
options(nostack, preserves_flags),
);
}
addr += CACHE_LINE_SIZE;
}
// Instruction sync barrier ensures subsequent fetches see the new code.
unsafe {
core::arch::asm!("isync", options(nostack, preserves_flags));
}
}
}
global_asm!(include_str!("hexagon/func_macro.s"), options(raw));
global_asm!(