1use crate::abi::Abi;
2use crate::error::{err, err_nt};
3use crate::translator::intrinsics::{Intrinsics, type_to_llvm};
4use inkwell::{
5 AddressSpace,
6 attributes::{Attribute, AttributeLoc},
7 builder::Builder,
8 context::Context,
9 types::{AnyType, BasicMetadataTypeEnum, BasicType, FunctionType, StructType},
10 values::{BasicValue, BasicValueEnum, CallSiteValue, FloatValue, IntValue, VectorValue},
11};
12use wasmer_types::{CompileError, FunctionType as FuncSig, Type};
13use wasmer_vm::VMOffsets;
14
15use std::convert::TryInto;
16
17pub(crate) struct RiscvSystemV {
19 pub(crate) is_riscv64: bool,
20}
21
22impl Abi for RiscvSystemV {
23 fn func_type_to_llvm<'ctx>(
25 &self,
26 context: &'ctx Context,
27 intrinsics: &Intrinsics<'ctx>,
28 offsets: Option<&VMOffsets>,
29 sig: &FuncSig,
30 include_m0_param: bool,
31 ) -> Result<(FunctionType<'ctx>, Vec<(Attribute, AttributeLoc)>), CompileError> {
32 let user_param_types = sig.params().iter().map(|&ty| type_to_llvm(intrinsics, ty));
33
34 let mut param_types = vec![Ok(intrinsics.ptr_ty.as_basic_type_enum())];
35 if include_m0_param {
36 param_types.push(Ok(intrinsics.ptr_ty.as_basic_type_enum()));
37 }
38
39 let mut extra_params = param_types.len();
40 let param_types = param_types.into_iter().chain(user_param_types);
41
42 let vmctx_attributes = |i: u32| {
44 vec![
45 (
46 context.create_enum_attribute(Attribute::get_named_enum_kind_id("nofree"), 0),
47 AttributeLoc::Param(i),
48 ),
49 (
50 if let Some(offsets) = offsets {
51 context.create_enum_attribute(
52 Attribute::get_named_enum_kind_id("dereferenceable"),
53 offsets.size_of_vmctx().into(),
54 )
55 } else {
56 context
57 .create_enum_attribute(Attribute::get_named_enum_kind_id("nonnull"), 0)
58 },
59 AttributeLoc::Param(i),
60 ),
61 (
62 context.create_enum_attribute(
63 Attribute::get_named_enum_kind_id("align"),
64 std::mem::align_of::<wasmer_vm::VMContext>()
65 .try_into()
66 .unwrap(),
67 ),
68 AttributeLoc::Param(i),
69 ),
70 ]
71 };
72
73 let sig_returns_bitwidths = sig
74 .results()
75 .iter()
76 .map(|ty| match ty {
77 Type::I32 | Type::F32 | Type::ExceptionRef => 32,
78 Type::I64 | Type::F64 => 64,
79 Type::V128 => 128,
80 Type::ExternRef | Type::FuncRef => {
81 if self.is_riscv64 {
82 64
83 } else {
84 32
85 }
86 } })
88 .collect::<Vec<i32>>();
89
90 let (fn_type, mut attributes) = match sig_returns_bitwidths.as_slice() {
91 [] => (
92 intrinsics.void_ty.fn_type(
93 param_types
94 .map(|v| v.map(Into::into))
95 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
96 .as_slice(),
97 false,
98 ),
99 vmctx_attributes(0),
100 ),
101 [_] => {
102 let single_value = sig.results()[0];
103 (
104 type_to_llvm(intrinsics, single_value)?.fn_type(
105 param_types
106 .map(|v| v.map(Into::into))
107 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
108 .as_slice(),
109 false,
110 ),
111 vmctx_attributes(0),
112 )
113 }
114 [32, 64] | [64, 32] | [64, 64] => {
115 let basic_types: Vec<_> = sig
116 .results()
117 .iter()
118 .map(|&ty| type_to_llvm(intrinsics, ty))
119 .collect::<Result<_, _>>()?;
120
121 (
122 context.struct_type(&basic_types, false).fn_type(
123 param_types
124 .map(|v| v.map(Into::into))
125 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
126 .as_slice(),
127 false,
128 ),
129 vmctx_attributes(0),
130 )
131 }
132 [32, 32] if sig.results()[0] == Type::F32 && sig.results()[1] == Type::F32 => (
133 intrinsics.f32_ty.vec_type(2).fn_type(
134 param_types
135 .map(|v| v.map(Into::into))
136 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
137 .as_slice(),
138 false,
139 ),
140 vmctx_attributes(0),
141 ),
142 [32, 32] => (
143 intrinsics.i64_ty.fn_type(
144 param_types
145 .map(|v| v.map(Into::into))
146 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
147 .as_slice(),
148 false,
149 ),
150 vmctx_attributes(0),
151 ),
152 [32, 32, 32 | 64] if sig.results()[0] == Type::F32 && sig.results()[1] == Type::F32 => {
153 (
154 context
155 .struct_type(
156 &[
157 intrinsics.f32_ty.vec_type(2).as_basic_type_enum(),
158 type_to_llvm(intrinsics, sig.results()[2])?,
159 ],
160 false,
161 )
162 .fn_type(
163 param_types
164 .map(|v| v.map(Into::into))
165 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
166 .as_slice(),
167 false,
168 ),
169 vmctx_attributes(0),
170 )
171 }
172 [32, 32, 32 | 64] => (
173 context
174 .struct_type(
175 &[
176 intrinsics.i64_ty.as_basic_type_enum(),
177 type_to_llvm(intrinsics, sig.results()[2])?,
178 ],
179 false,
180 )
181 .fn_type(
182 param_types
183 .map(|v| v.map(Into::into))
184 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
185 .as_slice(),
186 false,
187 ),
188 vmctx_attributes(0),
189 ),
190 [64, 32, 32] if sig.results()[1] == Type::F32 && sig.results()[2] == Type::F32 => (
191 context
192 .struct_type(
193 &[
194 type_to_llvm(intrinsics, sig.results()[0])?,
195 intrinsics.f32_ty.vec_type(2).as_basic_type_enum(),
196 ],
197 false,
198 )
199 .fn_type(
200 param_types
201 .map(|v| v.map(Into::into))
202 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
203 .as_slice(),
204 false,
205 ),
206 vmctx_attributes(0),
207 ),
208 [64, 32, 32] => (
209 context
210 .struct_type(
211 &[
212 type_to_llvm(intrinsics, sig.results()[0])?,
213 intrinsics.i64_ty.as_basic_type_enum(),
214 ],
215 false,
216 )
217 .fn_type(
218 param_types
219 .map(|v| v.map(Into::into))
220 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
221 .as_slice(),
222 false,
223 ),
224 vmctx_attributes(0),
225 ),
226 [32, 32, 32, 32] => (
227 context
228 .struct_type(
229 &[
230 if sig.results()[0] == Type::F32 && sig.results()[1] == Type::F32 {
231 intrinsics.f32_ty.vec_type(2).as_basic_type_enum()
232 } else {
233 intrinsics.i64_ty.as_basic_type_enum()
234 },
235 if sig.results()[2] == Type::F32 && sig.results()[3] == Type::F32 {
236 intrinsics.f32_ty.vec_type(2).as_basic_type_enum()
237 } else {
238 intrinsics.i64_ty.as_basic_type_enum()
239 },
240 ],
241 false,
242 )
243 .fn_type(
244 param_types
245 .map(|v| v.map(Into::into))
246 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
247 .as_slice(),
248 false,
249 ),
250 vmctx_attributes(0),
251 ),
252 _ => {
253 let basic_types: Vec<_> = sig
254 .results()
255 .iter()
256 .map(|&ty| type_to_llvm(intrinsics, ty))
257 .collect::<Result<_, _>>()?;
258
259 let sret = context.struct_type(&basic_types, false);
260 let sret_ptr = context.ptr_type(AddressSpace::default());
261
262 let param_types =
263 std::iter::once(Ok(sret_ptr.as_basic_type_enum())).chain(param_types);
264 extra_params += 1;
265
266 let mut attributes = vec![(
267 context.create_type_attribute(
268 Attribute::get_named_enum_kind_id("sret"),
269 sret.as_any_type_enum(),
270 ),
271 AttributeLoc::Param(0),
272 )];
273 attributes.append(&mut vmctx_attributes(1));
274
275 (
276 intrinsics.void_ty.fn_type(
277 param_types
278 .map(|v| v.map(Into::into))
279 .collect::<Result<Vec<BasicMetadataTypeEnum>, _>>()?
280 .as_slice(),
281 false,
282 ),
283 attributes,
284 )
285 }
286 };
287
288 if self.is_riscv64 {
293 for (i, ty) in sig.params().iter().enumerate() {
294 let i = (i + extra_params) as u32;
295 if matches!(ty, Type::I32) {
296 attributes.push((
297 context
298 .create_enum_attribute(Attribute::get_named_enum_kind_id("signext"), 0),
299 AttributeLoc::Param(i),
300 ));
301 attributes.push((
302 context
303 .create_enum_attribute(Attribute::get_named_enum_kind_id("noundef"), 0),
304 AttributeLoc::Param(i),
305 ));
306 }
307 }
308 }
309
310 Ok((fn_type, attributes))
311 }
312
313 fn rets_from_call<'ctx>(
315 &self,
316 builder: &Builder<'ctx>,
317 intrinsics: &Intrinsics<'ctx>,
318 call_site: CallSiteValue<'ctx>,
319 func_sig: &FuncSig,
320 ) -> Result<Vec<BasicValueEnum<'ctx>>, CompileError> {
321 let split_i64 =
322 |value: IntValue<'ctx>| -> Result<(IntValue<'ctx>, IntValue<'ctx>), CompileError> {
323 assert!(value.get_type() == intrinsics.i64_ty);
324 let low = err!(builder.build_int_truncate(value, intrinsics.i32_ty, ""));
325 let lshr = err!(builder.build_right_shift(
326 value,
327 intrinsics.i64_ty.const_int(32, false),
328 false,
329 ""
330 ));
331 let high = err!(builder.build_int_truncate(lshr, intrinsics.i32_ty, ""));
332 Ok((low, high))
333 };
334
335 let f32x2_ty = intrinsics.f32_ty.vec_type(2).as_basic_type_enum();
336 let extract_f32x2 = |value: VectorValue<'ctx>| -> Result<(FloatValue<'ctx>, FloatValue<'ctx>), CompileError> {
337 assert!(value.get_type() == f32x2_ty.into_vector_type());
338 let ret0 = err!(builder
339 .build_extract_element(value, intrinsics.i32_ty.const_int(0, false), ""))
340 .into_float_value();
341 let ret1 = err!(builder
342 .build_extract_element(value, intrinsics.i32_ty.const_int(1, false), ""))
343 .into_float_value();
344 Ok((ret0, ret1))
345 };
346
347 let casted =
348 |value: BasicValueEnum<'ctx>, ty: Type| -> Result<BasicValueEnum<'ctx>, CompileError> {
349 match ty {
350 Type::I32 => {
351 assert!(
352 value.get_type() == intrinsics.i32_ty.as_basic_type_enum()
353 || value.get_type() == intrinsics.f32_ty.as_basic_type_enum()
354 );
355 err_nt!(builder.build_bit_cast(value, intrinsics.i32_ty, ""))
356 }
357 Type::F32 => {
358 assert!(
359 value.get_type() == intrinsics.i32_ty.as_basic_type_enum()
360 || value.get_type() == intrinsics.f32_ty.as_basic_type_enum()
361 );
362 err_nt!(builder.build_bit_cast(value, intrinsics.f32_ty, ""))
363 }
364 _ => panic!("should only be called to repack 32-bit values"),
365 }
366 };
367
368 if let Some(basic_value) = call_site.try_as_basic_value().basic() {
369 if func_sig.results().len() > 1 {
370 if basic_value.get_type() == intrinsics.i64_ty.as_basic_type_enum() {
371 assert!(func_sig.results().len() == 2);
372 let value = basic_value.into_int_value();
373 let (low, high) = split_i64(value)?;
374 let low = casted(low.into(), func_sig.results()[0])?;
375 let high = casted(high.into(), func_sig.results()[1])?;
376 return Ok(vec![low, high]);
377 }
378 if basic_value.get_type() == f32x2_ty {
379 assert!(func_sig.results().len() == 2);
380 let (ret0, ret1) = extract_f32x2(basic_value.into_vector_value())?;
381 return Ok(vec![ret0.into(), ret1.into()]);
382 }
383 let struct_value = basic_value.into_struct_value();
384 let rets = (0..struct_value.get_type().count_fields())
385 .map(|i| builder.build_extract_value(struct_value, i, "").unwrap())
386 .collect::<Vec<_>>();
387 let func_sig_returns_bitwidths = func_sig
388 .results()
389 .iter()
390 .map(|ty| match ty {
391 Type::I32 | Type::F32 | Type::ExceptionRef => 32,
392 Type::I64 | Type::F64 => 64,
393 Type::V128 => 128,
394 Type::ExternRef | Type::FuncRef => {
395 if self.is_riscv64 {
396 64
397 } else {
398 32
399 }
400 } })
402 .collect::<Vec<i32>>();
403
404 let ret = match func_sig_returns_bitwidths.as_slice() {
405 [32, 64] | [64, 32] | [64, 64] => {
406 assert!(func_sig.results().len() == 2);
407 vec![rets[0], rets[1]]
408 }
409 [32, 32, _]
410 if rets[0].get_type()
411 == intrinsics.f32_ty.vec_type(2).as_basic_type_enum() =>
412 {
413 assert!(func_sig.results().len() == 3);
414 let (rets0, rets1) = extract_f32x2(rets[0].into_vector_value())?;
415 vec![rets0.into(), rets1.into(), rets[1]]
416 }
417 [32, 32, _] => {
418 assert!(func_sig.results().len() == 3);
419 let (low, high) = split_i64(rets[0].into_int_value())?;
420 let low = casted(low.into(), func_sig.results()[0])?;
421 let high = casted(high.into(), func_sig.results()[1])?;
422 vec![low, high, rets[1]]
423 }
424 [64, 32, 32]
425 if rets[1].get_type()
426 == intrinsics.f32_ty.vec_type(2).as_basic_type_enum() =>
427 {
428 assert!(func_sig.results().len() == 3);
429 let (rets1, rets2) = extract_f32x2(rets[1].into_vector_value())?;
430 vec![rets[0], rets1.into(), rets2.into()]
431 }
432 [64, 32, 32] => {
433 assert!(func_sig.results().len() == 3);
434 let (rets1, rets2) = split_i64(rets[1].into_int_value())?;
435 let rets1 = casted(rets1.into(), func_sig.results()[1])?;
436 let rets2 = casted(rets2.into(), func_sig.results()[2])?;
437 vec![rets[0], rets1, rets2]
438 }
439 [32, 32, 32, 32] => {
440 assert!(func_sig.results().len() == 4);
441 let (low0, high0) = if rets[0].get_type()
442 == intrinsics.f32_ty.vec_type(2).as_basic_type_enum()
443 {
444 let (x, y) = extract_f32x2(rets[0].into_vector_value())?;
445 (x.into(), y.into())
446 } else {
447 let (x, y) = split_i64(rets[0].into_int_value())?;
448 (x.into(), y.into())
449 };
450 let (low1, high1) = if rets[1].get_type()
451 == intrinsics.f32_ty.vec_type(2).as_basic_type_enum()
452 {
453 let (x, y) = extract_f32x2(rets[1].into_vector_value())?;
454 (x.into(), y.into())
455 } else {
456 let (x, y) = split_i64(rets[1].into_int_value())?;
457 (x.into(), y.into())
458 };
459 let low0 = casted(low0, func_sig.results()[0])?;
460 let high0 = casted(high0, func_sig.results()[1])?;
461 let low1 = casted(low1, func_sig.results()[2])?;
462 let high1 = casted(high1, func_sig.results()[3])?;
463 vec![low0, high0, low1, high1]
464 }
465 _ => unreachable!("expected an sret for this type"),
466 };
467
468 Ok(ret)
469 } else {
470 assert!(func_sig.results().len() == 1);
471 Ok(vec![basic_value])
472 }
473 } else {
474 assert!(call_site.count_arguments() > 0); if call_site
476 .get_enum_attribute(
477 AttributeLoc::Param(0),
478 Attribute::get_named_enum_kind_id("sret"),
479 )
480 .is_some()
481 {
482 let sret_ty = call_site
483 .try_as_basic_value()
484 .unwrap_instruction()
485 .get_operand(0)
486 .unwrap()
487 .unwrap_value();
488 let sret = sret_ty.into_pointer_value();
489 let llvm_results: Vec<_> = func_sig
491 .results()
492 .iter()
493 .map(|x| type_to_llvm(intrinsics, *x).unwrap())
494 .collect();
495 let struct_type = intrinsics
496 .i32_ty
497 .get_context()
498 .struct_type(llvm_results.as_slice(), false);
499
500 let struct_value =
501 err!(builder.build_load(struct_type, sret, "")).into_struct_value();
502 let mut rets: Vec<_> = Vec::new();
503 for i in 0..struct_value.get_type().count_fields() {
504 let value = builder.build_extract_value(struct_value, i, "").unwrap();
505 rets.push(value);
506 }
507 assert!(func_sig.results().len() == rets.len());
508 Ok(rets)
509 } else {
510 assert!(func_sig.results().is_empty());
511 Ok(vec![])
512 }
513 }
514 }
515
516 fn pack_values_for_register_return<'ctx>(
517 &self,
518 intrinsics: &Intrinsics<'ctx>,
519 builder: &Builder<'ctx>,
520 values: &[BasicValueEnum<'ctx>],
521 func_type: &FunctionType<'ctx>,
522 ) -> Result<BasicValueEnum<'ctx>, CompileError> {
523 let is_32 = |value: BasicValueEnum| {
524 (value.is_pointer_value() && !self.is_riscv64)
525 || (value.is_int_value() && value.into_int_value().get_type() == intrinsics.i32_ty)
526 || (value.is_float_value()
527 && value.into_float_value().get_type() == intrinsics.f32_ty)
528 };
529 let is_64 = |value: BasicValueEnum| {
530 (value.is_pointer_value() && self.is_riscv64)
531 || (value.is_int_value() && value.into_int_value().get_type() == intrinsics.i64_ty)
532 || (value.is_float_value()
533 && value.into_float_value().get_type() == intrinsics.f64_ty)
534 };
535 let is_f32 = |value: BasicValueEnum| {
536 value.is_float_value() && value.into_float_value().get_type() == intrinsics.f32_ty
537 };
538
539 let pack_i32s = |low: BasicValueEnum<'ctx>, high: BasicValueEnum<'ctx>| {
540 assert!(low.get_type() == intrinsics.i32_ty.as_basic_type_enum());
541 assert!(high.get_type() == intrinsics.i32_ty.as_basic_type_enum());
542 let (low, high) = (low.into_int_value(), high.into_int_value());
543 let low = err!(builder.build_int_z_extend(low, intrinsics.i64_ty, ""));
544 let high = err!(builder.build_int_z_extend(high, intrinsics.i64_ty, ""));
545 let high =
546 err!(builder.build_left_shift(high, intrinsics.i64_ty.const_int(32, false), ""));
547 err_nt!(
548 builder
549 .build_or(low, high, "")
550 .map(|v| v.as_basic_value_enum())
551 )
552 };
553
554 let pack_f32s = |first: BasicValueEnum<'ctx>,
555 second: BasicValueEnum<'ctx>|
556 -> Result<BasicValueEnum<'ctx>, CompileError> {
557 assert!(first.get_type() == intrinsics.f32_ty.as_basic_type_enum());
558 assert!(second.get_type() == intrinsics.f32_ty.as_basic_type_enum());
559 let (first, second) = (first.into_float_value(), second.into_float_value());
560 let vec_ty = intrinsics.f32_ty.vec_type(2);
561 let vec = err!(builder.build_insert_element(
562 vec_ty.get_undef(),
563 first,
564 intrinsics.i32_zero,
565 ""
566 ));
567 err_nt!(
568 builder
569 .build_insert_element(vec, second, intrinsics.i32_ty.const_int(1, false), "")
570 .map(|v| v.as_basic_value_enum())
571 )
572 };
573
574 let build_struct = |ty: StructType<'ctx>, values: &[BasicValueEnum<'ctx>]| {
575 let mut struct_value = ty.get_undef();
576 for (i, v) in values.iter().enumerate() {
577 struct_value = builder
578 .build_insert_value(struct_value, *v, i as u32, "")
579 .unwrap()
580 .into_struct_value();
581 }
582 struct_value.as_basic_value_enum()
583 };
584
585 Ok(match *values {
586 [one_value] => one_value,
587 [v1, v2] if is_f32(v1) && is_f32(v2) => pack_f32s(v1, v2)?,
588 [v1, v2] if is_32(v1) && is_32(v2) => {
589 let v1 = err!(builder.build_bit_cast(v1, intrinsics.i32_ty, ""));
590 let v2 = err!(builder.build_bit_cast(v2, intrinsics.i32_ty, ""));
591 pack_i32s(v1, v2)?
592 }
593 [v1, v2] => {
594 assert!(!(is_32(v1) && is_32(v2)));
595 build_struct(
596 func_type.get_return_type().unwrap().into_struct_type(),
597 &[v1, v2],
598 )
599 }
600 [v1, v2, v3] if is_f32(v1) && is_f32(v2) => build_struct(
601 func_type.get_return_type().unwrap().into_struct_type(),
602 &[pack_f32s(v1, v2)?, v3],
603 ),
604 [v1, v2, v3] if is_32(v1) && is_32(v2) => {
605 let v1 = err!(builder.build_bit_cast(v1, intrinsics.i32_ty, ""));
606 let v2 = err!(builder.build_bit_cast(v2, intrinsics.i32_ty, ""));
607 build_struct(
608 func_type.get_return_type().unwrap().into_struct_type(),
609 &[pack_i32s(v1, v2)?, v3],
610 )
611 }
612 [v1, v2, v3] if is_64(v1) && is_f32(v2) && is_f32(v3) => build_struct(
613 func_type.get_return_type().unwrap().into_struct_type(),
614 &[v1, pack_f32s(v2, v3)?],
615 ),
616 [v1, v2, v3] if is_64(v1) && is_32(v2) && is_32(v3) => {
617 let v2 = err!(builder.build_bit_cast(v2, intrinsics.i32_ty, ""));
618 let v3 = err!(builder.build_bit_cast(v3, intrinsics.i32_ty, ""));
619 build_struct(
620 func_type.get_return_type().unwrap().into_struct_type(),
621 &[v1, pack_i32s(v2, v3)?],
622 )
623 }
624 [v1, v2, v3, v4] if is_32(v1) && is_32(v2) && is_32(v3) && is_32(v4) => {
625 let v1v2_pack = if is_f32(v1) && is_f32(v2) {
626 pack_f32s(v1, v2)?
627 } else {
628 let v1 = err!(builder.build_bit_cast(v1, intrinsics.i32_ty, ""));
629 let v2 = err!(builder.build_bit_cast(v2, intrinsics.i32_ty, ""));
630 pack_i32s(v1, v2)?
631 };
632 let v3v4_pack = if is_f32(v3) && is_f32(v4) {
633 pack_f32s(v3, v4)?
634 } else {
635 let v3 = err!(builder.build_bit_cast(v3, intrinsics.i32_ty, ""));
636 let v4 = err!(builder.build_bit_cast(v4, intrinsics.i32_ty, ""));
637 pack_i32s(v3, v4)?
638 };
639 build_struct(
640 func_type.get_return_type().unwrap().into_struct_type(),
641 &[v1v2_pack, v3v4_pack],
642 )
643 }
644 _ => {
645 unreachable!("called to perform register return on struct return or void function")
646 }
647 })
648 }
649}