cranelift_codegen/isa/riscv64/
mod.rs1use crate::dominator_tree::DominatorTree;
4use crate::ir::{Function, Type};
5use crate::isa::riscv64::settings as riscv_settings;
6use crate::isa::{
7 Builder as IsaBuilder, FunctionAlignment, IsaFlagsHashKey, OwnedTargetIsa, TargetIsa,
8};
9use crate::machinst::CompiledCode;
10use crate::machinst::{
11 CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet, TextSectionBuilder, VCode,
12 compile,
13};
14use crate::result::CodegenResult;
15use crate::settings::{self as shared_settings, Flags};
16use crate::{CodegenError, ir};
17use alloc::string::String;
18use alloc::{boxed::Box, vec::Vec};
19use core::fmt;
20use cranelift_control::ControlPlane;
21use target_lexicon::{Architecture, Triple};
22mod abi;
23pub(crate) mod inst;
24mod lower;
25mod settings;
26#[cfg(feature = "unwind")]
27use crate::isa::unwind::systemv;
28
29use self::inst::EmitInfo;
30
31pub struct Riscv64Backend {
33 triple: Triple,
34 flags: shared_settings::Flags,
35 isa_flags: riscv_settings::Flags,
36}
37
38impl Riscv64Backend {
39 pub fn new_with_flags(
41 triple: Triple,
42 flags: shared_settings::Flags,
43 isa_flags: riscv_settings::Flags,
44 ) -> Riscv64Backend {
45 Riscv64Backend {
46 triple,
47 flags,
48 isa_flags,
49 }
50 }
51
52 fn compile_vcode(
55 &self,
56 func: &Function,
57 domtree: &DominatorTree,
58 regalloc_ctx: &mut regalloc2::Ctx,
59 ctrl_plane: &mut ControlPlane,
60 ) -> CodegenResult<VCode<inst::Inst>> {
61 let emit_info = EmitInfo::new(self.flags.clone(), self.isa_flags.clone());
62 let sigs = SigSet::new::<abi::Riscv64MachineDeps>(func, &self.flags)?;
63 let abi = abi::Riscv64Callee::new(func, self, &self.isa_flags, &sigs)?;
64 compile::compile::<Riscv64Backend>(
65 func,
66 domtree,
67 regalloc_ctx,
68 self,
69 abi,
70 emit_info,
71 sigs,
72 ctrl_plane,
73 )
74 }
75}
76
77impl TargetIsa for Riscv64Backend {
78 fn compile_function(
79 &self,
80 func: &Function,
81 domtree: &DominatorTree,
82 regalloc_ctx: &mut regalloc2::Ctx,
83 want_disasm: bool,
84 ctrl_plane: &mut ControlPlane,
85 ) -> CodegenResult<CompiledCodeStencil> {
86 let vcode = self.compile_vcode(func, domtree, regalloc_ctx, ctrl_plane)?;
87
88 let want_disasm = want_disasm || log::log_enabled!(log::Level::Debug);
89 let emit_result = vcode.emit(®alloc_ctx.output, want_disasm, &self.flags, ctrl_plane)?;
90 let value_labels_ranges = emit_result.value_labels_ranges;
91 let buffer = emit_result.buffer;
92
93 if let Some(disasm) = emit_result.disasm.as_ref() {
94 log::debug!("disassembly:\n{disasm}");
95 }
96
97 Ok(CompiledCodeStencil(CompiledCode {
98 buffer,
99 vcode: emit_result.disasm,
100 value_labels_ranges,
101 bb_starts: emit_result.bb_offsets,
102 bb_edges: emit_result.bb_edges,
103 }))
104 }
105
106 fn name(&self) -> &'static str {
107 "riscv64"
108 }
109 fn dynamic_vector_bytes(&self, _dynamic_ty: ir::Type) -> u32 {
110 16
111 }
112
113 fn triple(&self) -> &Triple {
114 &self.triple
115 }
116
117 fn flags(&self) -> &shared_settings::Flags {
118 &self.flags
119 }
120
121 fn isa_flags(&self) -> Vec<shared_settings::Value> {
122 self.isa_flags.iter().collect()
123 }
124
125 fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> {
126 IsaFlagsHashKey(self.isa_flags.hash_key())
127 }
128
129 #[cfg(feature = "unwind")]
130 fn emit_unwind_info(
131 &self,
132 result: &CompiledCode,
133 kind: crate::isa::unwind::UnwindInfoKind,
134 ) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
135 use crate::isa::unwind::UnwindInfo;
136 use crate::isa::unwind::UnwindInfoKind;
137 Ok(match kind {
138 UnwindInfoKind::SystemV => {
139 let mapper = self::inst::unwind::systemv::RegisterMapper;
140 Some(UnwindInfo::SystemV(
141 crate::isa::unwind::systemv::create_unwind_info_from_insts(
142 &result.buffer.unwind_info[..],
143 result.buffer.data().len(),
144 &mapper,
145 )?,
146 ))
147 }
148 UnwindInfoKind::Windows => None,
149 _ => None,
150 })
151 }
152
153 #[cfg(feature = "unwind")]
154 fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
155 Some(inst::unwind::systemv::create_cie())
156 }
157
158 fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
159 Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs))
160 }
161
162 #[cfg(feature = "unwind")]
163 fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> {
164 inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)
165 }
166
167 fn function_alignment(&self) -> FunctionAlignment {
168 inst::Inst::function_alignment()
169 }
170
171 fn page_size_align_log2(&self) -> u8 {
172 debug_assert_eq!(1 << 12, 0x1000);
173 12
174 }
175
176 #[cfg(feature = "disas")]
177 fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {
178 use capstone::prelude::*;
179 let mut cs_builder = Capstone::new().riscv().mode(arch::riscv::ArchMode::RiscV64);
180
181 let uses_compressed = self
190 .isa_flags()
191 .iter()
192 .filter(|f| ["has_zca", "has_zcb", "has_zcd"].contains(&f.name))
193 .any(|f| f.as_bool().unwrap_or(false));
194 if uses_compressed {
195 cs_builder = cs_builder.extra_mode([arch::riscv::ArchExtraMode::RiscVC].into_iter());
196 }
197
198 let mut cs = cs_builder.build()?;
199
200 cs.set_skipdata(true)?;
204 Ok(cs)
205 }
206
207 fn pretty_print_reg(&self, reg: Reg, _size: u8) -> String {
208 format!("{reg:?}")
210 }
211
212 fn has_native_fma(&self) -> bool {
213 true
214 }
215
216 fn has_round(&self) -> bool {
217 true
218 }
219
220 fn has_blendv_lowering(&self, _: Type) -> bool {
221 false
222 }
223
224 fn has_x86_pshufb_lowering(&self) -> bool {
225 false
226 }
227
228 fn has_x86_pmulhrsw_lowering(&self) -> bool {
229 false
230 }
231
232 fn has_x86_pmaddubsw_lowering(&self) -> bool {
233 false
234 }
235
236 fn default_argument_extension(&self) -> ir::ArgumentExtension {
237 ir::ArgumentExtension::Sext
247 }
248}
249
250impl fmt::Display for Riscv64Backend {
251 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252 f.debug_struct("MachBackend")
253 .field("name", &self.name())
254 .field("triple", &self.triple())
255 .field("flags", &format!("{}", self.flags()))
256 .finish()
257 }
258}
259
260pub fn isa_builder(triple: Triple) -> IsaBuilder {
262 match triple.architecture {
263 Architecture::Riscv64(..) => {}
264 _ => unreachable!(),
265 }
266 IsaBuilder {
267 triple,
268 setup: riscv_settings::builder(),
269 constructor: isa_constructor,
270 }
271}
272
273fn isa_constructor(
274 triple: Triple,
275 shared_flags: Flags,
276 builder: &shared_settings::Builder,
277) -> CodegenResult<OwnedTargetIsa> {
278 let isa_flags = riscv_settings::Flags::new(&shared_flags, builder);
279
280 if !(isa_flags.has_m()
292 && isa_flags.has_a()
293 && isa_flags.has_f()
294 && isa_flags.has_d()
295 && isa_flags.has_zicsr()
296 && isa_flags.has_zifencei())
297 {
298 return Err(CodegenError::Unsupported(
299 "The RISC-V Backend currently requires all the features in the G Extension enabled"
300 .into(),
301 ));
302 }
303
304 let backend = Riscv64Backend::new_with_flags(triple, shared_flags, isa_flags);
305 Ok(backend.wrapped())
306}