Merge pull request #1879 from heiher/loong-simd-unified-types

loongarch: Use unified data types for SIMD intrinsics
This commit is contained in:
Folkert de Vries
2025-07-25 13:46:59 +00:00
committed by GitHub
5 changed files with 4782 additions and 4524 deletions

View File

@@ -1,33 +1,140 @@
types! {
#![unstable(feature = "stdarch_loongarch", issue = "117427")]
/// LOONGARCH-specific 256-bit wide vector of 32 packed `i8`.
pub struct v32i8(32 x pub(crate) i8);
/// 256-bit wide integer vector type, LoongArch-specific
///
/// This type is the same as the `__m256i` type defined in `lasxintrin.h`,
/// representing a 256-bit SIMD register. Usage of this type typically
/// occurs in conjunction with the `lasx` target features for LoongArch.
///
/// Internally this type may be viewed as:
///
/// * `i8x32` - thirty two `i8` values packed together
/// * `i16x16` - sixteen `i16` values packed together
/// * `i32x8` - eight `i32` values packed together
/// * `i64x4` - four `i64` values packed together
///
/// (as well as unsigned versions). Each intrinsic may interpret the
/// internal bits differently, check the documentation of the intrinsic
/// to see how it's being used.
///
/// The in-memory representation of this type is the same as the one of an
/// equivalent array (i.e. the in-memory order of elements is the same, and
/// there is no padding); however, the alignment is different and equal to
/// the size of the type. Note that the ABI for function calls may *not* be
/// the same.
///
/// Note that this means that an instance of `m256i` typically just means
/// a "bag of bits" which is left up to interpretation at the point of use.
///
/// Most intrinsics using `m256i` are prefixed with `lasx_` and the integer
/// types tend to correspond to suffixes like "b", "h", "w" or "d".
pub struct m256i(4 x i64);
/// LOONGARCH-specific 256-bit wide vector of 16 packed `i16`.
pub struct v16i16(16 x pub(crate) i16);
/// 256-bit wide set of eight `f32` values, LoongArch-specific
///
/// This type is the same as the `__m256` type defined in `lasxintrin.h`,
/// representing a 256-bit SIMD register which internally consists of
/// eight packed `f32` instances. Usage of this type typically occurs in
/// conjunction with the `lasx` target features for LoongArch.
///
/// Note that unlike `m256i`, the integer version of the 256-bit registers,
/// this `m256` type has *one* interpretation. Each instance of `m256`
/// always corresponds to `f32x8`, or eight `f32` values packed together.
///
/// The in-memory representation of this type is the same as the one of an
/// equivalent array (i.e. the in-memory order of elements is the same, and
/// there is no padding between two consecutive elements); however, the
/// alignment is different and equal to the size of the type. Note that the
/// ABI for function calls may *not* be the same.
///
/// Most intrinsics using `m256` are prefixed with `lasx_` and are
/// suffixed with "s".
pub struct m256(8 x f32);
/// LOONGARCH-specific 256-bit wide vector of 8 packed `i32`.
pub struct v8i32(8 x pub(crate) i32);
/// 256-bit wide set of four `f64` values, LoongArch-specific
///
/// This type is the same as the `__m256d` type defined in `lasxintrin.h`,
/// representing a 256-bit SIMD register which internally consists of
/// four packed `f64` instances. Usage of this type typically occurs in
/// conjunction with the `lasx` target features for LoongArch.
///
/// Note that unlike `m256i`, the integer version of the 256-bit registers,
/// this `m256d` type has *one* interpretation. Each instance of `m256d`
/// always corresponds to `f64x4`, or four `f64` values packed together.
///
/// The in-memory representation of this type is the same as the one of an
/// equivalent array (i.e. the in-memory order of elements is the same, and
/// there is no padding); however, the alignment is different and equal to
/// the size of the type. Note that the ABI for function calls may *not* be
/// the same.
///
/// Most intrinsics using `m256d` are prefixed with `lasx_` and are suffixed
/// with "d". Not to be confused with "d" which is used for `m256i`.
pub struct m256d(4 x f64);
/// LOONGARCH-specific 256-bit wide vector of 4 packed `i64`.
pub struct v4i64(4 x pub(crate) i64);
/// LOONGARCH-specific 256-bit wide vector of 32 packed `u8`.
pub struct v32u8(32 x pub(crate) u8);
/// LOONGARCH-specific 256-bit wide vector of 16 packed `u16`.
pub struct v16u16(16 x pub(crate) u16);
/// LOONGARCH-specific 256-bit wide vector of 8 packed `u32`.
pub struct v8u32(8 x pub(crate) u32);
/// LOONGARCH-specific 256-bit wide vector of 4 packed `u64`.
pub struct v4u64(4 x pub(crate) u64);
/// LOONGARCH-specific 128-bit wide vector of 8 packed `f32`.
pub struct v8f32(8 x pub(crate) f32);
/// LOONGARCH-specific 256-bit wide vector of 4 packed `f64`.
pub struct v4f64(4 x pub(crate) f64);
}
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v32i8([i8; 32]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v16i16([i16; 16]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v8i32([i32; 8]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v4i64([i64; 4]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v32u8([u8; 32]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v16u16([u16; 16]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v8u32([u32; 8]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v4u64([u64; 4]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v8f32([f32; 8]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v4f64([f64; 4]);
// These type aliases are provided solely for transitional compatibility.
// They are temporary and will be removed when appropriate.
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v32i8 = m256i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v16i16 = m256i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v8i32 = m256i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v4i64 = m256i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v32u8 = m256i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v16u16 = m256i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v8u32 = m256i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v4u64 = m256i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v8f32 = m256;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v4f64 = m256d;

View File

@@ -1,33 +1,140 @@
types! {
#![unstable(feature = "stdarch_loongarch", issue = "117427")]
/// LOONGARCH-specific 128-bit wide vector of 16 packed `i8`.
pub struct v16i8(16 x pub(crate) i8);
/// 128-bit wide integer vector type, LoongArch-specific
///
/// This type is the same as the `__m128i` type defined in `lsxintrin.h`,
/// representing a 128-bit SIMD register. Usage of this type typically
/// occurs in conjunction with the `lsx` and higher target features for
/// LoongArch.
///
/// Internally this type may be viewed as:
///
/// * `i8x16` - sixteen `i8` values packed together
/// * `i16x8` - eight `i16` values packed together
/// * `i32x4` - four `i32` values packed together
/// * `i64x2` - two `i64` values packed together
///
/// (as well as unsigned versions). Each intrinsic may interpret the
/// internal bits differently, check the documentation of the intrinsic
/// to see how it's being used.
///
/// The in-memory representation of this type is the same as the one of an
/// equivalent array (i.e. the in-memory order of elements is the same, and
/// there is no padding); however, the alignment is different and equal to
/// the size of the type. Note that the ABI for function calls may *not* be
/// the same.
///
/// Note that this means that an instance of `m128i` typically just means
/// a "bag of bits" which is left up to interpretation at the point of use.
///
/// Most intrinsics using `m128i` are prefixed with `lsx_` and the integer
/// types tend to correspond to suffixes like "b", "h", "w" or "d".
pub struct m128i(2 x i64);
/// LOONGARCH-specific 128-bit wide vector of 8 packed `i16`.
pub struct v8i16(8 x pub(crate) i16);
/// 128-bit wide set of four `f32` values, LoongArch-specific
///
/// This type is the same as the `__m128` type defined in `lsxintrin.h`,
/// representing a 128-bit SIMD register which internally consists of
/// four packed `f32` instances. Usage of this type typically occurs in
/// conjunction with the `lsx` and higher target features for LoongArch.
///
/// Note that unlike `m128i`, the integer version of the 128-bit registers,
/// this `m128` type has *one* interpretation. Each instance of `m128`
/// corresponds to `f32x4`, or four `f32` values packed together.
///
/// The in-memory representation of this type is the same as the one of an
/// equivalent array (i.e. the in-memory order of elements is the same, and
/// there is no padding); however, the alignment is different and equal to
/// the size of the type. Note that the ABI for function calls may *not* be
/// the same.
///
/// Most intrinsics using `m128` are prefixed with `lsx_` and are suffixed
/// with "s".
pub struct m128(4 x f32);
/// LOONGARCH-specific 128-bit wide vector of 4 packed `i32`.
pub struct v4i32(4 x pub(crate) i32);
/// LOONGARCH-specific 128-bit wide vector of 2 packed `i64`.
pub struct v2i64(2 x pub(crate) i64);
/// LOONGARCH-specific 128-bit wide vector of 16 packed `u8`.
pub struct v16u8(16 x pub(crate) u8);
/// LOONGARCH-specific 128-bit wide vector of 8 packed `u16`.
pub struct v8u16(8 x pub(crate) u16);
/// LOONGARCH-specific 128-bit wide vector of 4 packed `u32`.
pub struct v4u32(4 x pub(crate) u32);
/// LOONGARCH-specific 128-bit wide vector of 2 packed `u64`.
pub struct v2u64(2 x pub(crate) u64);
/// LOONGARCH-specific 128-bit wide vector of 4 packed `f32`.
pub struct v4f32(4 x pub(crate) f32);
/// LOONGARCH-specific 128-bit wide vector of 2 packed `f64`.
pub struct v2f64(2 x pub(crate) f64);
/// 128-bit wide set of two `f64` values, LoongArch-specific
///
/// This type is the same as the `__m128d` type defined in `lsxintrin.h`,
/// representing a 128-bit SIMD register which internally consists of
/// two packed `f64` instances. Usage of this type typically occurs in
/// conjunction with the `lsx` and higher target features for LoongArch.
///
/// Note that unlike `m128i`, the integer version of the 128-bit registers,
/// this `m128d` type has *one* interpretation. Each instance of `m128d`
/// always corresponds to `f64x2`, or two `f64` values packed together.
///
/// The in-memory representation of this type is the same as the one of an
/// equivalent array (i.e. the in-memory order of elements is the same, and
/// there is no padding); however, the alignment is different and equal to
/// the size of the type. Note that the ABI for function calls may *not* be
/// the same.
///
/// Most intrinsics using `m128d` are prefixed with `lsx_` and are suffixed
/// with "d". Not to be confused with "d" which is used for `m128i`.
pub struct m128d(2 x f64);
}
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v16i8([i8; 16]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v8i16([i16; 8]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v4i32([i32; 4]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v2i64([i64; 2]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v16u8([u8; 16]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v8u16([u16; 8]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v4u32([u32; 4]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v2u64([u64; 2]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v4f32([f32; 4]);
#[allow(non_camel_case_types)]
#[repr(simd)]
pub(crate) struct __v2f64([f64; 2]);
// These type aliases are provided solely for transitional compatibility.
// They are temporary and will be removed when appropriate.
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v16i8 = m128i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v8i16 = m128i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v4i32 = m128i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v2i64 = m128i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v16u8 = m128i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v8u16 = m128i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v4u32 = m128i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v2u64 = m128i;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v4f32 = m128;
#[allow(non_camel_case_types)]
#[unstable(feature = "stdarch_loongarch", issue = "117427")]
pub type v2f64 = m128d;

View File

@@ -156,6 +156,7 @@ fn gen_bind(in_file: String, ext_name: &str) -> io::Result<()> {
// OUT_DIR=`pwd`/crates/core_arch cargo run -p stdarch-gen-loongarch -- {in_file}
// ```
use crate::mem::transmute;
use super::types::*;
"#
));
@@ -239,38 +240,63 @@ fn gen_bind_body(
para_num: i32,
target: TargetFeature,
) -> (String, String) {
let type_to_rst = |t: &str, s: bool| -> &str {
match (t, s) {
("V16QI", _) => "v16i8",
("V32QI", _) => "v32i8",
("V8HI", _) => "v8i16",
("V16HI", _) => "v16i16",
("V4SI", _) => "v4i32",
("V8SI", _) => "v8i32",
("V2DI", _) => "v2i64",
("V4DI", _) => "v4i64",
("UV16QI", _) => "v16u8",
("UV32QI", _) => "v32u8",
("UV8HI", _) => "v8u16",
("UV16HI", _) => "v16u16",
("UV4SI", _) => "v4u32",
("UV8SI", _) => "v8u32",
("UV2DI", _) => "v2u64",
("UV4DI", _) => "v4u64",
("SI", _) => "i32",
("DI", _) => "i64",
("USI", _) => "u32",
("UDI", _) => "u64",
("V4SF", _) => "v4f32",
("V8SF", _) => "v8f32",
("V2DF", _) => "v2f64",
("V4DF", _) => "v4f64",
("UQI", _) => "u32",
("QI", _) => "i32",
("CVPOINTER", false) => "*const i8",
("CVPOINTER", true) => "*mut i8",
("HI", _) => "i32",
(_, _) => panic!("unknown type: {t}"),
enum TypeKind {
Vector,
Intrinsic,
}
use TypeKind::*;
let type_to_rst = |t: &str, s: bool, k: TypeKind| -> &str {
match (t, s, k) {
("V16QI", _, Vector) => "__v16i8",
("V16QI", _, Intrinsic) => "m128i",
("V32QI", _, Vector) => "__v32i8",
("V32QI", _, Intrinsic) => "m256i",
("V8HI", _, Vector) => "__v8i16",
("V8HI", _, Intrinsic) => "m128i",
("V16HI", _, Vector) => "__v16i16",
("V16HI", _, Intrinsic) => "m256i",
("V4SI", _, Vector) => "__v4i32",
("V4SI", _, Intrinsic) => "m128i",
("V8SI", _, Vector) => "__v8i32",
("V8SI", _, Intrinsic) => "m256i",
("V2DI", _, Vector) => "__v2i64",
("V2DI", _, Intrinsic) => "m128i",
("V4DI", _, Vector) => "__v4i64",
("V4DI", _, Intrinsic) => "m256i",
("UV16QI", _, Vector) => "__v16u8",
("UV16QI", _, Intrinsic) => "m128i",
("UV32QI", _, Vector) => "__v32u8",
("UV32QI", _, Intrinsic) => "m256i",
("UV8HI", _, Vector) => "__v8u16",
("UV8HI", _, Intrinsic) => "m128i",
("UV16HI", _, Vector) => "__v16u16",
("UV16HI", _, Intrinsic) => "m256i",
("UV4SI", _, Vector) => "__v4u32",
("UV4SI", _, Intrinsic) => "m128i",
("UV8SI", _, Vector) => "__v8u32",
("UV8SI", _, Intrinsic) => "m256i",
("UV2DI", _, Vector) => "__v2u64",
("UV2DI", _, Intrinsic) => "m128i",
("UV4DI", _, Vector) => "__v4u64",
("UV4DI", _, Intrinsic) => "m256i",
("SI", _, _) => "i32",
("DI", _, _) => "i64",
("USI", _, _) => "u32",
("UDI", _, _) => "u64",
("V4SF", _, Vector) => "__v4f32",
("V4SF", _, Intrinsic) => "m128",
("V8SF", _, Vector) => "__v8f32",
("V8SF", _, Intrinsic) => "m256",
("V2DF", _, Vector) => "__v2f64",
("V2DF", _, Intrinsic) => "m128d",
("V4DF", _, Vector) => "__v4f64",
("V4DF", _, Intrinsic) => "m256d",
("UQI", _, _) => "u32",
("QI", _, _) => "i32",
("CVPOINTER", false, _) => "*const i8",
("CVPOINTER", true, _) => "*mut i8",
("HI", _, _) => "i32",
(_, _, _) => panic!("unknown type: {t}"),
}
};
@@ -281,27 +307,27 @@ fn gen_bind_body(
let fn_output = if out_t.to_lowercase() == "void" {
String::new()
} else {
format!(" -> {}", type_to_rst(out_t, is_store))
format!(" -> {}", type_to_rst(out_t, is_store, Vector))
};
let fn_inputs = match para_num {
1 => format!("(a: {})", type_to_rst(in_t[0], is_store)),
1 => format!("(a: {})", type_to_rst(in_t[0], is_store, Vector)),
2 => format!(
"(a: {}, b: {})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store)
type_to_rst(in_t[0], is_store, Vector),
type_to_rst(in_t[1], is_store, Vector)
),
3 => format!(
"(a: {}, b: {}, c: {})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[2], is_store)
type_to_rst(in_t[0], is_store, Vector),
type_to_rst(in_t[1], is_store, Vector),
type_to_rst(in_t[2], is_store, Vector)
),
4 => format!(
"(a: {}, b: {}, c: {}, d: {})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[2], is_store),
type_to_rst(in_t[3], is_store)
type_to_rst(in_t[0], is_store, Vector),
type_to_rst(in_t[1], is_store, Vector),
type_to_rst(in_t[2], is_store, Vector),
type_to_rst(in_t[3], is_store, Vector)
),
_ => panic!("unsupported parameter number"),
};
@@ -330,34 +356,40 @@ fn gen_bind_body(
let fn_output = if out_t.to_lowercase() == "void" {
String::new()
} else {
format!("-> {} ", type_to_rst(out_t, is_store))
format!("-> {} ", type_to_rst(out_t, is_store, Intrinsic))
};
let mut fn_inputs = match para_num {
1 => format!("(a: {})", type_to_rst(in_t[0], is_store)),
1 => format!("(a: {})", type_to_rst(in_t[0], is_store, Intrinsic)),
2 => format!(
"(a: {}, b: {})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store)
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic)
),
3 => format!(
"(a: {}, b: {}, c: {})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[2], is_store)
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic),
type_to_rst(in_t[2], is_store, Intrinsic)
),
4 => format!(
"(a: {}, b: {}, c: {}, d: {})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[2], is_store),
type_to_rst(in_t[3], is_store)
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic),
type_to_rst(in_t[2], is_store, Intrinsic),
type_to_rst(in_t[3], is_store, Intrinsic)
),
_ => panic!("unsupported parameter number"),
};
if para_num == 1 && in_t[0] == "HI" {
fn_inputs = match asm_fmts[1].as_str() {
"si13" | "i13" => format!("<const IMM_S13: {}>()", type_to_rst(in_t[0], is_store)),
"si10" => format!("<const IMM_S10: {}>()", type_to_rst(in_t[0], is_store)),
"si13" | "i13" => format!(
"<const IMM_S13: {}>()",
type_to_rst(in_t[0], is_store, Intrinsic)
),
"si10" => format!(
"<const IMM_S10: {}>()",
type_to_rst(in_t[0], is_store, Intrinsic)
),
_ => panic!("unsupported assembly format: {}", asm_fmts[1]),
};
rustc_legacy_const_generics = "rustc_legacy_const_generics(0)";
@@ -365,8 +397,8 @@ fn gen_bind_body(
fn_inputs = if asm_fmts[2].starts_with("ui") {
format!(
"<const IMM{2}: {1}>(a: {0})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic),
asm_fmts[2].get(2..).unwrap()
)
} else {
@@ -377,8 +409,8 @@ fn gen_bind_body(
fn_inputs = if asm_fmts[2].starts_with("si") {
format!(
"<const IMM_S{2}: {1}>(a: {0})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic),
asm_fmts[2].get(2..).unwrap()
)
} else {
@@ -389,8 +421,8 @@ fn gen_bind_body(
fn_inputs = if asm_fmts[2].starts_with("si") {
format!(
"<const IMM_S{2}: {1}>(mem_addr: {0})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic),
asm_fmts[2].get(2..).unwrap()
)
} else {
@@ -401,8 +433,8 @@ fn gen_bind_body(
fn_inputs = match asm_fmts[2].as_str() {
"rk" => format!(
"(mem_addr: {}, b: {})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store)
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic)
),
_ => panic!("unsupported assembly format: {}", asm_fmts[2]),
};
@@ -410,9 +442,9 @@ fn gen_bind_body(
fn_inputs = if asm_fmts[2].starts_with("ui") {
format!(
"<const IMM{3}: {2}>(a: {0}, b: {1})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[2], is_store),
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic),
type_to_rst(in_t[2], is_store, Intrinsic),
asm_fmts[2].get(2..).unwrap()
)
} else {
@@ -423,9 +455,9 @@ fn gen_bind_body(
fn_inputs = match asm_fmts[2].as_str() {
"si12" => format!(
"<const IMM_S12: {2}>(a: {0}, mem_addr: {1})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[2], is_store)
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic),
type_to_rst(in_t[2], is_store, Intrinsic)
),
_ => panic!("unsupported assembly format: {}", asm_fmts[2]),
};
@@ -434,9 +466,9 @@ fn gen_bind_body(
fn_inputs = match asm_fmts[2].as_str() {
"rk" => format!(
"(a: {}, mem_addr: {}, b: {})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[2], is_store)
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic),
type_to_rst(in_t[2], is_store, Intrinsic)
),
_ => panic!("unsupported assembly format: {}", asm_fmts[2]),
};
@@ -444,10 +476,10 @@ fn gen_bind_body(
fn_inputs = match (asm_fmts[2].as_str(), current_name.chars().last().unwrap()) {
("si8", t) => format!(
"<const IMM_S8: {2}, const IMM{4}: {3}>(a: {0}, mem_addr: {1})",
type_to_rst(in_t[0], is_store),
type_to_rst(in_t[1], is_store),
type_to_rst(in_t[2], is_store),
type_to_rst(in_t[3], is_store),
type_to_rst(in_t[0], is_store, Intrinsic),
type_to_rst(in_t[1], is_store, Intrinsic),
type_to_rst(in_t[2], is_store, Intrinsic),
type_to_rst(in_t[3], is_store, Intrinsic),
type_to_imm(t),
),
(_, _) => panic!(
@@ -466,10 +498,16 @@ fn gen_bind_body(
let unsafe_end = if !is_mem { " }" } else { "" };
let mut call_params = {
match para_num {
1 => format!("{unsafe_start}__{current_name}(a){unsafe_end}"),
2 => format!("{unsafe_start}__{current_name}(a, b){unsafe_end}"),
3 => format!("{unsafe_start}__{current_name}(a, b, c){unsafe_end}"),
4 => format!("{unsafe_start}__{current_name}(a, b, c, d){unsafe_end}"),
1 => format!("{unsafe_start}transmute(__{current_name}(transmute(a))){unsafe_end}"),
2 => format!(
"{unsafe_start}transmute(__{current_name}(transmute(a), transmute(b))){unsafe_end}"
),
3 => format!(
"{unsafe_start}transmute(__{current_name}(transmute(a), transmute(b), transmute(c))){unsafe_end}"
),
4 => format!(
"{unsafe_start}transmute(__{current_name}(transmute(a), transmute(b), transmute(c), transmute(d))){unsafe_end}"
),
_ => panic!("unsupported parameter number"),
}
};
@@ -477,12 +515,12 @@ fn gen_bind_body(
call_params = match asm_fmts[1].as_str() {
"si10" => {
format!(
"static_assert_simm_bits!(IMM_S10, 10);\n {unsafe_start}__{current_name}(IMM_S10){unsafe_end}"
"static_assert_simm_bits!(IMM_S10, 10);\n {unsafe_start}transmute(__{current_name}(IMM_S10)){unsafe_end}"
)
}
"i13" => {
format!(
"static_assert_simm_bits!(IMM_S13, 13);\n {unsafe_start}__{current_name}(IMM_S13){unsafe_end}"
"static_assert_simm_bits!(IMM_S13, 13);\n {unsafe_start}transmute(__{current_name}(IMM_S13)){unsafe_end}"
)
}
_ => panic!("unsupported assembly format: {}", asm_fmts[2]),
@@ -490,7 +528,7 @@ fn gen_bind_body(
} else if para_num == 2 && (in_t[1] == "UQI" || in_t[1] == "USI") {
call_params = if asm_fmts[2].starts_with("ui") {
format!(
"static_assert_uimm_bits!(IMM{0}, {0});\n {unsafe_start}__{current_name}(a, IMM{0}){unsafe_end}",
"static_assert_uimm_bits!(IMM{0}, {0});\n {unsafe_start}transmute(__{current_name}(transmute(a), IMM{0})){unsafe_end}",
asm_fmts[2].get(2..).unwrap()
)
} else {
@@ -500,7 +538,7 @@ fn gen_bind_body(
call_params = match asm_fmts[2].as_str() {
"si5" => {
format!(
"static_assert_simm_bits!(IMM_S5, 5);\n {unsafe_start}__{current_name}(a, IMM_S5){unsafe_end}"
"static_assert_simm_bits!(IMM_S5, 5);\n {unsafe_start}transmute(__{current_name}(transmute(a), IMM_S5)){unsafe_end}"
)
}
_ => panic!("unsupported assembly format: {}", asm_fmts[2]),
@@ -508,7 +546,7 @@ fn gen_bind_body(
} else if para_num == 2 && in_t[0] == "CVPOINTER" && in_t[1] == "SI" {
call_params = if asm_fmts[2].starts_with("si") {
format!(
"static_assert_simm_bits!(IMM_S{0}, {0});\n {unsafe_start}__{current_name}(mem_addr, IMM_S{0}){unsafe_end}",
"static_assert_simm_bits!(IMM_S{0}, {0});\n {unsafe_start}transmute(__{current_name}(mem_addr, IMM_S{0})){unsafe_end}",
asm_fmts[2].get(2..).unwrap()
)
} else {
@@ -516,13 +554,15 @@ fn gen_bind_body(
}
} else if para_num == 2 && in_t[0] == "CVPOINTER" && in_t[1] == "DI" {
call_params = match asm_fmts[2].as_str() {
"rk" => format!("{unsafe_start}__{current_name}(mem_addr, b){unsafe_end}"),
"rk" => format!(
"{unsafe_start}transmute(__{current_name}(mem_addr, transmute(b))){unsafe_end}"
),
_ => panic!("unsupported assembly format: {}", asm_fmts[2]),
};
} else if para_num == 3 && (in_t[2] == "USI" || in_t[2] == "UQI") {
call_params = if asm_fmts[2].starts_with("ui") {
format!(
"static_assert_uimm_bits!(IMM{0}, {0});\n {unsafe_start}__{current_name}(a, b, IMM{0}){unsafe_end}",
"static_assert_uimm_bits!(IMM{0}, {0});\n {unsafe_start}transmute(__{current_name}(transmute(a), transmute(b), IMM{0})){unsafe_end}",
asm_fmts[2].get(2..).unwrap()
)
} else {
@@ -531,19 +571,21 @@ fn gen_bind_body(
} else if para_num == 3 && in_t[1] == "CVPOINTER" && in_t[2] == "SI" {
call_params = match asm_fmts[2].as_str() {
"si12" => format!(
"static_assert_simm_bits!(IMM_S12, 12);\n {unsafe_start}__{current_name}(a, mem_addr, IMM_S12){unsafe_end}"
"static_assert_simm_bits!(IMM_S12, 12);\n {unsafe_start}transmute(__{current_name}(transmute(a), mem_addr, IMM_S12)){unsafe_end}"
),
_ => panic!("unsupported assembly format: {}", asm_fmts[2]),
};
} else if para_num == 3 && in_t[1] == "CVPOINTER" && in_t[2] == "DI" {
call_params = match asm_fmts[2].as_str() {
"rk" => format!("{unsafe_start}__{current_name}(a, mem_addr, b){unsafe_end}"),
"rk" => format!(
"{unsafe_start}transmute(__{current_name}(transmute(a), mem_addr, transmute(b))){unsafe_end}"
),
_ => panic!("unsupported assembly format: {}", asm_fmts[2]),
};
} else if para_num == 4 {
call_params = match (asm_fmts[2].as_str(), current_name.chars().last().unwrap()) {
("si8", t) => format!(
"static_assert_simm_bits!(IMM_S8, 8);\n static_assert_uimm_bits!(IMM{0}, {0});\n {unsafe_start}__{current_name}(a, mem_addr, IMM_S8, IMM{0}){unsafe_end}",
"static_assert_simm_bits!(IMM_S8, 8);\n static_assert_uimm_bits!(IMM{0}, {0});\n {unsafe_start}transmute(__{current_name}(transmute(a), mem_addr, IMM_S8, IMM{0})){unsafe_end}",
type_to_imm(t)
),
(_, _) => panic!(