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