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