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