use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone)]
pub struct IntrinsicDesc2 {
pub name: String,
pub return_type: String,
pub param_types: Vec<String>,
pub attributes: Vec<IntrinsicAttribute2>,
pub targets: Vec<String>,
pub category: IntrinsicCategory2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IntrinsicAttribute2 {
NoUnwind,
ReadNone,
ReadOnly,
NoMem,
ArgMemOnly,
WillReturn,
NoSync,
NoFree,
InaccessibleMemOnly,
Speculatable,
Convergent,
NoDuplicate,
IntrNoMem,
IntrReadMem,
IntrWriteMem,
IntrArgMemOnly,
IntrWillReturn,
IntrNoCallback,
IntrCold,
}
impl fmt::Display for IntrinsicAttribute2 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum IntrinsicCategory2 {
Matrix,
VectorPredication,
ConstrainedFP,
HardwareLoop,
StackMap,
AssumeBundles,
DebugInfo,
ObjCARC,
PointerAuth,
ConvergenceControl,
}
impl fmt::Display for IntrinsicCategory2 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
pub fn matrix_multiply(
return_type: &str,
a_type: &str,
b_type: &str,
m: u32,
n: u32,
k: u32,
) -> IntrinsicDesc2 {
IntrinsicDesc2 {
name: format!(
"llvm.matrix.multiply.{}.{}.{}.{}.{}",
return_type, a_type, b_type, m, n
),
return_type: return_type.to_string(),
param_types: vec![
a_type.to_string(),
b_type.to_string(),
"i32".to_string(),
"i32".to_string(),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::Matrix,
}
}
pub fn matrix_transpose(return_type: &str, src_type: &str, rows: u32, cols: u32) -> IntrinsicDesc2 {
IntrinsicDesc2 {
name: format!(
"llvm.matrix.transpose.{}.{}.{}.{}",
return_type, src_type, rows, cols
),
return_type: return_type.to_string(),
param_types: vec![src_type.to_string(), "i32".to_string(), "i32".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::Matrix,
}
}
pub fn matrix_column_major_load(
return_type: &str,
ptr_type: &str,
stride: u64,
is_volatile: bool,
rows: u32,
cols: u32,
) -> IntrinsicDesc2 {
IntrinsicDesc2 {
name: format!(
"llvm.matrix.column.major.load.{}.{}.{}.{}.{}",
return_type,
ptr_type,
stride,
if is_volatile { 1 } else { 0 },
rows
),
return_type: return_type.to_string(),
param_types: vec![
ptr_type.to_string(),
"i64".to_string(),
"i1".to_string(),
"i32".to_string(),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
if is_volatile {
IntrinsicAttribute2::ArgMemOnly
} else {
IntrinsicAttribute2::ReadOnly
},
],
targets: vec![],
category: IntrinsicCategory2::Matrix,
}
}
pub fn matrix_column_major_store(
matrix_type: &str,
ptr_type: &str,
stride: u64,
is_volatile: bool,
rows: u32,
cols: u32,
) -> IntrinsicDesc2 {
IntrinsicDesc2 {
name: format!(
"llvm.matrix.column.major.store.{}.{}.{}.{}.{}",
matrix_type,
ptr_type,
stride,
if is_volatile { 1 } else { 0 },
rows
),
return_type: "void".to_string(),
param_types: vec![
matrix_type.to_string(),
ptr_type.to_string(),
"i64".to_string(),
"i1".to_string(),
"i32".to_string(),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::Matrix,
}
}
pub fn all_matrix_intrinsics() -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
for m in [2u32, 4, 8] {
for n in [2u32, 4, 8] {
for k in [2u32, 4, 8] {
result.push(matrix_multiply(
&format!("<{} x float>", m * n),
&format!("<{} x float>", m * k),
&format!("<{} x float>", k * n),
m,
n,
k,
));
}
}
}
for rows in [2u32, 4, 8, 16] {
for cols in [2u32, 4, 8, 16] {
if rows != cols {
result.push(matrix_transpose(
&format!("<{} x float>", rows * cols),
&format!("<{} x float>", rows * cols),
rows,
cols,
));
}
}
}
for rows in [2u32, 4, 8] {
for cols in [2u32, 4, 8] {
result.push(matrix_column_major_load(
&format!("<{} x float>", rows * cols),
"ptr",
cols as u64 * 4,
false,
rows,
cols,
));
result.push(matrix_column_major_store(
&format!("<{} x float>", rows * cols),
"ptr",
cols as u64 * 4,
false,
rows,
cols,
));
}
}
result
}
#[derive(Debug, Clone)]
pub struct VPIntrinsicFamily {
pub base_name: String,
pub has_mask: bool,
pub has_passthru: bool,
pub operand_count: u8,
pub is_commutative: bool,
}
pub fn make_vp_intrinsics(family: &VPIntrinsicFamily) -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
let type_variants = [
"i8",
"i16",
"i32",
"i64",
"half",
"float",
"double",
"<2 x i32>",
"<4 x i32>",
"<8 x i32>",
"<2 x float>",
"<4 x float>",
"<8 x float>",
"<2 x double>",
"<4 x double>",
];
for ty in &type_variants {
let mut param_types = Vec::new();
param_types.push(format!("<vscale x {} x i1>", get_element_count_str(ty)));
param_types.push("i32".to_string());
for _ in 0..family.operand_count {
param_types.push(format!("<vscale x {} x {}>", get_element_count_str(ty), ty));
}
let attr = vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
];
result.push(IntrinsicDesc2 {
name: format!("llvm.vp.{}.{}", family.base_name, mangle_type(ty)),
return_type: format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
param_types,
attributes: attr,
targets: vec![],
category: IntrinsicCategory2::VectorPredication,
});
}
result
}
fn get_element_count_str(ty: &str) -> String {
if ty.starts_with('<') {
let parts: Vec<&str> = ty.split('x').collect();
parts[0].trim().to_string()
} else {
"1".to_string()
}
}
fn mangle_type(ty: &str) -> String {
ty.replace('<', "_").replace('>', "_").replace(' ', "")
}
pub fn vp_integer_arith_intrinsics() -> Vec<IntrinsicDesc2> {
let families = [
("add", 2, true),
("sub", 2, false),
("mul", 2, true),
("sdiv", 2, false),
("udiv", 2, false),
("srem", 2, false),
("urem", 2, false),
("and", 2, true),
("or", 2, true),
("xor", 2, true),
("ashr", 2, false),
("lshr", 2, false),
("shl", 2, false),
("smin", 2, true),
("smax", 2, true),
("umin", 2, true),
("umax", 2, true),
];
let mut result = Vec::new();
for (name, ops, comm) in &families {
let family = VPIntrinsicFamily {
base_name: name.to_string(),
has_mask: true,
has_passthru: true,
operand_count: *ops,
is_commutative: *comm,
};
result.extend(make_vp_intrinsics(&family));
}
result
}
pub fn vp_fp_arith_intrinsics() -> Vec<IntrinsicDesc2> {
let families = [
("fadd", 2, true),
("fsub", 2, false),
("fmul", 2, true),
("fdiv", 2, false),
("frem", 2, false),
("fneg", 1, false),
("fabs", 1, false),
("fminnum", 2, true),
("fmaxnum", 2, true),
("fcopysign", 2, false),
("sqrt", 1, false),
];
let mut result = Vec::new();
for (name, ops, comm) in &families {
let family = VPIntrinsicFamily {
base_name: name.to_string(),
has_mask: true,
has_passthru: true,
operand_count: *ops,
is_commutative: *comm,
};
result.extend(make_vp_fp_intrinsics(&family));
}
result
}
fn make_vp_fp_intrinsics(family: &VPIntrinsicFamily) -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
let type_variants = [
"half",
"float",
"double",
"<2 x float>",
"<4 x float>",
"<8 x float>",
"<2 x double>",
"<4 x double>",
];
for ty in &type_variants {
let mut param_types = Vec::new();
param_types.push(format!("<vscale x {} x i1>", get_element_count_str(ty)));
param_types.push("i32".to_string());
for _ in 0..family.operand_count {
param_types.push(format!("<vscale x {} x {}>", get_element_count_str(ty), ty));
}
result.push(IntrinsicDesc2 {
name: format!("llvm.vp.{}.{}", family.base_name, mangle_type(ty)),
return_type: format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
param_types,
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::VectorPredication,
});
}
result
}
pub fn vp_memory_intrinsics() -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
let load_store_types = [
"i8",
"i16",
"i32",
"i64",
"half",
"float",
"double",
"<2 x i32>",
"<4 x i32>",
"<8 x i32>",
"<2 x float>",
"<4 x float>",
"<8 x float>",
];
for ty in &load_store_types {
result.push(IntrinsicDesc2 {
name: format!("llvm.vp.load.{}", mangle_type(ty)),
return_type: format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
param_types: vec![
"ptr".to_string(),
format!("<vscale x {} x i1>", get_element_count_str(ty)),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ReadOnly,
],
targets: vec![],
category: IntrinsicCategory2::VectorPredication,
});
}
for ty in &load_store_types {
result.push(IntrinsicDesc2 {
name: format!("llvm.vp.store.{}", mangle_type(ty)),
return_type: "void".to_string(),
param_types: vec![
format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
"ptr".to_string(),
format!("<vscale x {} x i1>", get_element_count_str(ty)),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::VectorPredication,
});
}
for ty in &load_store_types {
result.push(IntrinsicDesc2 {
name: format!("llvm.vp.gather.{}", mangle_type(ty)),
return_type: format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
param_types: vec![
format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
"ptr".to_string(),
format!("<vscale x {} x i1>", get_element_count_str(ty)),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ReadOnly,
],
targets: vec![],
category: IntrinsicCategory2::VectorPredication,
});
}
for ty in &load_store_types {
result.push(IntrinsicDesc2 {
name: format!("llvm.vp.scatter.{}", mangle_type(ty)),
return_type: "void".to_string(),
param_types: vec![
format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
"ptr".to_string(),
format!("<vscale x {} x i1>", get_element_count_str(ty)),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::VectorPredication,
});
}
result
}
pub fn vp_reduce_intrinsics() -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
let reduce_ops = [
"add", "mul", "and", "or", "xor", "smin", "smax", "umin", "umax", "fadd", "fmul", "fmin",
"fmax",
];
let types = [
"i32",
"i64",
"float",
"double",
"<2 x i32>",
"<4 x i32>",
"<8 x i32>",
"<2 x float>",
"<4 x float>",
"<8 x float>",
];
for op in &reduce_ops {
for ty in &types {
let is_fp = op.starts_with('f') || ty.contains("float") || ty.contains("double");
let elem_ty = if ty.starts_with('<') {
ty.split("x ").nth(1).unwrap_or("i32")
} else {
ty
};
result.push(IntrinsicDesc2 {
name: format!("llvm.vp.reduce.{}.{}", op, mangle_type(ty)),
return_type: if is_fp {
format!("<vscale x 1 x {}>", elem_ty)
} else {
format!("<vscale x 1 x {}>", elem_ty)
},
param_types: vec![
format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
format!("<vscale x {} x i1>", get_element_count_str(ty)),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::VectorPredication,
});
}
}
result
}
pub fn vp_merge_selection_intrinsics() -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
let types = [
"i32",
"i64",
"float",
"double",
"<2 x i32>",
"<4 x i32>",
"<8 x i32>",
"<2 x float>",
"<4 x float>",
"<8 x float>",
];
for ty in &types {
result.push(IntrinsicDesc2 {
name: format!("llvm.vp.merge.{}", mangle_type(ty)),
return_type: format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
param_types: vec![
format!("<vscale x {} x i1>", get_element_count_str(ty)),
format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::VectorPredication,
});
}
for ty in &types {
result.push(IntrinsicDesc2 {
name: format!("llvm.vp.select.{}", mangle_type(ty)),
return_type: format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
param_types: vec![
format!("<vscale x {} x i1>", get_element_count_str(ty)),
format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
format!("<vscale x {} x {}>", get_element_count_str(ty), ty),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::VectorPredication,
});
}
result
}
pub fn all_vp_intrinsics() -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
result.extend(vp_integer_arith_intrinsics());
result.extend(vp_fp_arith_intrinsics());
result.extend(vp_memory_intrinsics());
result.extend(vp_reduce_intrinsics());
result.extend(vp_merge_selection_intrinsics());
result
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FPRoundingMode {
Dynamic = 0,
Tonearest = 1,
Downward = 2,
Upward = 3,
Towardzero = 4,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FPExceptionBehavior {
Ignore = 0,
Maytrap = 1,
Strict = 2,
}
pub fn constrained_fp_intrinsic(
op: &str,
return_type: &str,
operand_types: &[&str],
) -> IntrinsicDesc2 {
let mut param_types = Vec::new();
for ot in operand_types {
param_types.push(ot.to_string());
}
param_types.push("metadata".to_string()); param_types.push("metadata".to_string());
IntrinsicDesc2 {
name: format!("llvm.experimental.constrained.{}", op),
return_type: return_type.to_string(),
param_types,
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::ConstrainedFP,
}
}
pub fn all_constrained_fp_intrinsics() -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
let fp_types = ["half", "float", "double", "fp128", "x86_fp80"];
let binary_ops = ["fadd", "fsub", "fmul", "fdiv", "frem"];
let unary_ops = [
"sqrt",
"fabs",
"ceil",
"floor",
"trunc",
"round",
"roundeven",
"nearbyint",
"rint",
"lrint",
"llrint",
"lround",
"llround",
"fptrunc",
"fpext",
"fptoui",
"fptosi",
"uitofp",
"sitofp",
"fma",
];
let compare_ops = ["fcmps", "fcmp", "fcmps_unordered", "fcmp_unordered"];
for op in &binary_ops {
for ty in &fp_types {
result.push(constrained_fp_intrinsic(op, ty, &[ty, ty]));
}
}
for op in &unary_ops {
for ty in &fp_types {
match *op {
"fptrunc" => {
result.push(constrained_fp_intrinsic("fptrunc", "half", &["float"]));
result.push(constrained_fp_intrinsic("fptrunc", "float", &["double"]));
}
"fpext" => {
result.push(constrained_fp_intrinsic("fpext", "float", &["half"]));
result.push(constrained_fp_intrinsic("fpext", "double", &["float"]));
}
"fptoui" | "fptosi" => {
for int_ty in &["i32", "i64"] {
result.push(constrained_fp_intrinsic(op, int_ty, &[ty]));
}
}
"uitofp" | "sitofp" => {
for int_ty in &["i32", "i64"] {
result.push(constrained_fp_intrinsic(op, ty, &[int_ty]));
}
}
"fma" => {
result.push(constrained_fp_intrinsic("fma", ty, &[ty, ty, ty]));
}
_ => {
result.push(constrained_fp_intrinsic(op, ty, &[ty]));
}
}
}
}
for op in &compare_ops {
for ty in &fp_types {
result.push(constrained_fp_intrinsic(op, "i1", &[ty, ty]));
}
}
let special_ops = [
"pow", "powi", "exp", "exp2", "log", "log2", "log10", "sin", "cos",
];
for op in &special_ops {
for ty in &["float", "double"] {
if *op == "pow" || *op == "powi" {
let second_ty = if *op == "powi" { "i32" } else { *ty };
result.push(constrained_fp_intrinsic(op, ty, &[ty, second_ty]));
} else {
result.push(constrained_fp_intrinsic(op, ty, &[ty]));
}
}
}
result
}
pub fn hardware_loop_intrinsics() -> Vec<IntrinsicDesc2> {
vec![
IntrinsicDesc2 {
name: "llvm.set.loop.iterations.i32".to_string(),
return_type: "void".to_string(),
param_types: vec!["i32".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::HardwareLoop,
},
IntrinsicDesc2 {
name: "llvm.set.loop.iterations.i64".to_string(),
return_type: "void".to_string(),
param_types: vec!["i64".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::HardwareLoop,
},
IntrinsicDesc2 {
name: "llvm.loop.decrement.i32".to_string(),
return_type: "i32".to_string(),
param_types: vec!["i32".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::HardwareLoop,
},
IntrinsicDesc2 {
name: "llvm.loop.decrement.i64".to_string(),
return_type: "i64".to_string(),
param_types: vec!["i64".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::HardwareLoop,
},
IntrinsicDesc2 {
name: "llvm.loop.decrement.reg.i32.i32".to_string(),
return_type: "i32".to_string(),
param_types: vec!["i32".to_string(), "i32".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::HardwareLoop,
},
IntrinsicDesc2 {
name: "llvm.loop.decrement.reg.i64.i64".to_string(),
return_type: "i64".to_string(),
param_types: vec!["i64".to_string(), "i64".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::HardwareLoop,
},
]
}
pub fn stackmap_intrinsics() -> Vec<IntrinsicDesc2> {
vec![
IntrinsicDesc2 {
name: "llvm.experimental.stackmap".to_string(),
return_type: "void".to_string(),
param_types: vec![
"i64".to_string(), "i32".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::StackMap,
},
IntrinsicDesc2 {
name: "llvm.experimental.patchpoint.void".to_string(),
return_type: "void".to_string(),
param_types: vec![
"i64".to_string(), "i32".to_string(), "ptr".to_string(), "i32".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::StackMap,
},
IntrinsicDesc2 {
name: "llvm.experimental.patchpoint.i64".to_string(),
return_type: "i64".to_string(),
param_types: vec![
"i64".to_string(),
"i32".to_string(),
"ptr".to_string(),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::StackMap,
},
IntrinsicDesc2 {
name: "llvm.experimental.gc.statepoint.p0".to_string(),
return_type: "token".to_string(),
param_types: vec![
"i64".to_string(), "i32".to_string(), "ptr".to_string(), "i32".to_string(), "i32".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::StackMap,
},
]
}
pub fn gc_relocation_intrinsics() -> Vec<IntrinsicDesc2> {
vec![
IntrinsicDesc2 {
name: "llvm.experimental.gc.result.ptr".to_string(),
return_type: "ptr".to_string(),
param_types: vec!["token".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ReadNone,
],
targets: vec![],
category: IntrinsicCategory2::StackMap,
},
IntrinsicDesc2 {
name: "llvm.experimental.gc.result.i32".to_string(),
return_type: "i32".to_string(),
param_types: vec!["token".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ReadNone,
],
targets: vec![],
category: IntrinsicCategory2::StackMap,
},
IntrinsicDesc2 {
name: "llvm.experimental.gc.result.i64".to_string(),
return_type: "i64".to_string(),
param_types: vec!["token".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ReadNone,
],
targets: vec![],
category: IntrinsicCategory2::StackMap,
},
IntrinsicDesc2 {
name: "llvm.experimental.gc.relocate".to_string(),
return_type: "ptr".to_string(),
param_types: vec![
"token".to_string(), "i32".to_string(), "i32".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ReadNone,
],
targets: vec![],
category: IntrinsicCategory2::StackMap,
},
]
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AssumeBundleTag {
Align,
Dereferenceable,
DereferenceableOrNull,
NonNull,
SeparateStorage,
}
impl AssumeBundleTag {
pub fn tag_string(&self) -> &'static str {
match self {
AssumeBundleTag::Align => "align",
AssumeBundleTag::Dereferenceable => "dereferenceable",
AssumeBundleTag::DereferenceableOrNull => "dereferenceable_or_null",
AssumeBundleTag::NonNull => "nonnull",
AssumeBundleTag::SeparateStorage => "separate_storage",
}
}
}
#[derive(Debug, Clone)]
pub struct AssumeBundle {
pub tag: AssumeBundleTag,
pub args: Vec<AssumeBundleArg>,
}
#[derive(Debug, Clone)]
pub enum AssumeBundleArg {
Value(String),
Integer(u64),
Constant(String),
}
pub fn assume_bundle_intrinsics() -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
result.push(IntrinsicDesc2 {
name: "llvm.assume".to_string(),
return_type: "void".to_string(),
param_types: vec!["i1".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::InaccessibleMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::AssumeBundles,
});
result.push(IntrinsicDesc2 {
name: "llvm.assume [\"align\"(ptr, i64, i64)]".to_string(),
return_type: "void".to_string(),
param_types: vec![
"i1".to_string(),
"ptr".to_string(),
"i64".to_string(),
"i64".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::InaccessibleMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::AssumeBundles,
});
result.push(IntrinsicDesc2 {
name: "llvm.assume [\"dereferenceable\"(ptr, i64)]".to_string(),
return_type: "void".to_string(),
param_types: vec!["i1".to_string(), "ptr".to_string(), "i64".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::InaccessibleMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::AssumeBundles,
});
result.push(IntrinsicDesc2 {
name: "llvm.assume [\"nonnull\"(ptr)]".to_string(),
return_type: "void".to_string(),
param_types: vec!["i1".to_string(), "ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::InaccessibleMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::AssumeBundles,
});
result.push(IntrinsicDesc2 {
name: "llvm.assume [\"separate_storage\"(ptr, ptr)]".to_string(),
return_type: "void".to_string(),
param_types: vec!["i1".to_string(), "ptr".to_string(), "ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::InaccessibleMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::AssumeBundles,
});
result
}
pub fn debug_info_intrinsics_extended() -> Vec<IntrinsicDesc2> {
vec![
IntrinsicDesc2 {
name: "llvm.dbg.addr".to_string(),
return_type: "void".to_string(),
param_types: vec![
"metadata".to_string(), "metadata".to_string(), "metadata".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::NoFree,
],
targets: vec![],
category: IntrinsicCategory2::DebugInfo,
},
IntrinsicDesc2 {
name: "llvm.dbg.assign".to_string(),
return_type: "void".to_string(),
param_types: vec![
"metadata".to_string(), "metadata".to_string(), "metadata".to_string(), "metadata".to_string(), "metadata".to_string(), "metadata".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::NoFree,
],
targets: vec![],
category: IntrinsicCategory2::DebugInfo,
},
IntrinsicDesc2 {
name: "llvm.dbg.label".to_string(),
return_type: "void".to_string(),
param_types: vec![
"metadata".to_string(), "metadata".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::NoFree,
],
targets: vec![],
category: IntrinsicCategory2::DebugInfo,
},
]
}
pub fn objc_arc_intrinsics() -> Vec<IntrinsicDesc2> {
vec![
IntrinsicDesc2 {
name: "llvm.objc.clang.arc.use".to_string(),
return_type: "void".to_string(),
param_types: vec!["ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec![
"aarch64".to_string(),
"x86_64".to_string(),
"arm64".to_string(),
],
category: IntrinsicCategory2::ObjCARC,
},
IntrinsicDesc2 {
name: "llvm.objc.retain".to_string(),
return_type: "ptr".to_string(),
param_types: vec!["ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec!["aarch64".to_string(), "x86_64".to_string()],
category: IntrinsicCategory2::ObjCARC,
},
IntrinsicDesc2 {
name: "llvm.objc.release".to_string(),
return_type: "void".to_string(),
param_types: vec!["ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec!["aarch64".to_string(), "x86_64".to_string()],
category: IntrinsicCategory2::ObjCARC,
},
IntrinsicDesc2 {
name: "llvm.objc.autorelease".to_string(),
return_type: "ptr".to_string(),
param_types: vec!["ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec!["aarch64".to_string(), "x86_64".to_string()],
category: IntrinsicCategory2::ObjCARC,
},
IntrinsicDesc2 {
name: "llvm.objc.storeStrong".to_string(),
return_type: "void".to_string(),
param_types: vec!["ptr".to_string(), "ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec!["aarch64".to_string(), "x86_64".to_string()],
category: IntrinsicCategory2::ObjCARC,
},
IntrinsicDesc2 {
name: "llvm.objc.storeWeak".to_string(),
return_type: "void".to_string(),
param_types: vec!["ptr".to_string(), "ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec!["aarch64".to_string(), "x86_64".to_string()],
category: IntrinsicCategory2::ObjCARC,
},
IntrinsicDesc2 {
name: "llvm.objc.loadWeak".to_string(),
return_type: "ptr".to_string(),
param_types: vec!["ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec!["aarch64".to_string(), "x86_64".to_string()],
category: IntrinsicCategory2::ObjCARC,
},
]
}
pub fn pointer_auth_intrinsics() -> Vec<IntrinsicDesc2> {
vec![
IntrinsicDesc2 {
name: "llvm.ptrauth.sign".to_string(),
return_type: "i64".to_string(),
param_types: vec![
"i64".to_string(), "i32".to_string(), "i64".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec!["aarch64".to_string()],
category: IntrinsicCategory2::PointerAuth,
},
IntrinsicDesc2 {
name: "llvm.ptrauth.auth".to_string(),
return_type: "i64".to_string(),
param_types: vec![
"i64".to_string(), "i32".to_string(), "i64".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec!["aarch64".to_string()],
category: IntrinsicCategory2::PointerAuth,
},
IntrinsicDesc2 {
name: "llvm.ptrauth.resign".to_string(),
return_type: "i64".to_string(),
param_types: vec![
"i64".to_string(), "i32".to_string(), "i64".to_string(), "i32".to_string(), "i64".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec!["aarch64".to_string()],
category: IntrinsicCategory2::PointerAuth,
},
IntrinsicDesc2 {
name: "llvm.ptrauth.strip".to_string(),
return_type: "i64".to_string(),
param_types: vec![
"i64".to_string(), "i32".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec!["aarch64".to_string()],
category: IntrinsicCategory2::PointerAuth,
},
IntrinsicDesc2 {
name: "llvm.ptrauth.blend".to_string(),
return_type: "i64".to_string(),
param_types: vec![
"i64".to_string(), "i64".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec!["aarch64".to_string()],
category: IntrinsicCategory2::PointerAuth,
},
IntrinsicDesc2 {
name: "llvm.ptrauth.sign.generic".to_string(),
return_type: "i64".to_string(),
param_types: vec![
"i64".to_string(), "i64".to_string(), ],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec!["aarch64".to_string()],
category: IntrinsicCategory2::PointerAuth,
},
]
}
pub fn convergence_control_intrinsics() -> Vec<IntrinsicDesc2> {
vec![
IntrinsicDesc2 {
name: "llvm.experimental.convergence.entry".to_string(),
return_type: "token".to_string(),
param_types: vec![],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::Convergent,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::ConvergenceControl,
},
IntrinsicDesc2 {
name: "llvm.experimental.convergence.loop".to_string(),
return_type: "token".to_string(),
param_types: vec!["token".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::Convergent,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::ConvergenceControl,
},
IntrinsicDesc2 {
name: "llvm.experimental.convergence.anchor".to_string(),
return_type: "token".to_string(),
param_types: vec!["token".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::Convergent,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::ConvergenceControl,
},
IntrinsicDesc2 {
name: "llvm.experimental.convergence.control".to_string(),
return_type: "void".to_string(),
param_types: vec!["token".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::Convergent,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::ConvergenceControl,
},
IntrinsicDesc2 {
name: "llvm.experimental.convergence.begin".to_string(),
return_type: "token".to_string(),
param_types: vec!["token".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::Convergent,
IntrinsicAttribute2::IntrNoMem,
],
targets: vec![],
category: IntrinsicCategory2::ConvergenceControl,
},
IntrinsicDesc2 {
name: "llvm.experimental.convergence.end".to_string(),
return_type: "void".to_string(),
param_types: vec!["token".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::Convergent,
],
targets: vec![],
category: IntrinsicCategory2::ConvergenceControl,
},
]
}
pub struct IntrinsicDatabase2 {
pub matrix: Vec<IntrinsicDesc2>,
pub vp: Vec<IntrinsicDesc2>,
pub constrained_fp: Vec<IntrinsicDesc2>,
pub hw_loop: Vec<IntrinsicDesc2>,
pub stackmap: Vec<IntrinsicDesc2>,
pub gc: Vec<IntrinsicDesc2>,
pub assume: Vec<IntrinsicDesc2>,
pub debug: Vec<IntrinsicDesc2>,
pub objc_arc: Vec<IntrinsicDesc2>,
pub ptrauth: Vec<IntrinsicDesc2>,
pub convergence: Vec<IntrinsicDesc2>,
}
impl IntrinsicDatabase2 {
pub fn new() -> Self {
IntrinsicDatabase2 {
matrix: all_matrix_intrinsics(),
vp: all_vp_intrinsics(),
constrained_fp: all_constrained_fp_intrinsics(),
hw_loop: hardware_loop_intrinsics(),
stackmap: stackmap_intrinsics(),
gc: gc_relocation_intrinsics(),
assume: assume_bundle_intrinsics(),
debug: debug_info_intrinsics_extended(),
objc_arc: objc_arc_intrinsics(),
ptrauth: pointer_auth_intrinsics(),
convergence: convergence_control_intrinsics(),
}
}
pub fn total_count(&self) -> usize {
self.matrix.len()
+ self.vp.len()
+ self.constrained_fp.len()
+ self.hw_loop.len()
+ self.stackmap.len()
+ self.gc.len()
+ self.assume.len()
+ self.debug.len()
+ self.objc_arc.len()
+ self.ptrauth.len()
+ self.convergence.len()
}
pub fn find_by_name(&self, name: &str) -> Option<&IntrinsicDesc2> {
for list in [
&self.matrix,
&self.vp,
&self.constrained_fp,
&self.hw_loop,
&self.stackmap,
&self.gc,
&self.assume,
&self.debug,
&self.objc_arc,
&self.ptrauth,
&self.convergence,
] {
for desc in list {
if desc.name == name {
return Some(desc);
}
}
}
None
}
pub fn find_by_prefix(&self, prefix: &str) -> Vec<&IntrinsicDesc2> {
let mut result = Vec::new();
for list in [
&self.matrix,
&self.vp,
&self.constrained_fp,
&self.hw_loop,
&self.stackmap,
&self.gc,
&self.assume,
&self.debug,
&self.objc_arc,
&self.ptrauth,
&self.convergence,
] {
for desc in list {
if desc.name.starts_with(prefix) {
result.push(desc);
}
}
}
result
}
pub fn find_by_category(&self, category: IntrinsicCategory2) -> Vec<&IntrinsicDesc2> {
let list = match category {
IntrinsicCategory2::Matrix => &self.matrix,
IntrinsicCategory2::VectorPredication => &self.vp,
IntrinsicCategory2::ConstrainedFP => &self.constrained_fp,
IntrinsicCategory2::HardwareLoop => &self.hw_loop,
IntrinsicCategory2::StackMap => {
let mut result: Vec<&IntrinsicDesc2> = self.stackmap.iter().collect();
result.extend(self.gc.iter());
return result;
}
IntrinsicCategory2::AssumeBundles => &self.assume,
IntrinsicCategory2::DebugInfo => &self.debug,
IntrinsicCategory2::ObjCARC => &self.objc_arc,
IntrinsicCategory2::PointerAuth => &self.ptrauth,
IntrinsicCategory2::ConvergenceControl => &self.convergence,
};
list.iter().collect()
}
}
impl Default for IntrinsicDatabase2 {
fn default() -> Self {
Self::new()
}
}
pub fn extended_coroutine_intrinsics() -> Vec<IntrinsicDesc2> {
vec![
IntrinsicDesc2 {
name: "llvm.coro.async.size.replace".to_string(),
return_type: "i32".to_string(),
param_types: vec!["ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::ConvergenceControl,
},
IntrinsicDesc2 {
name: "llvm.coro.prepare.async".to_string(),
return_type: "ptr".to_string(),
param_types: vec!["ptr".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec![],
category: IntrinsicCategory2::ConvergenceControl,
},
IntrinsicDesc2 {
name: "llvm.coro.suspend.async".to_string(),
return_type: "i8".to_string(),
param_types: vec!["ptr".to_string(), "ptr".to_string(), "ptr".to_string()],
attributes: vec![IntrinsicAttribute2::NoUnwind],
targets: vec![],
category: IntrinsicCategory2::ConvergenceControl,
},
]
}
pub fn aarch64_sve_vp_intrinsics() -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
let sve_ops = [
"fadd", "fsub", "fmul", "fdiv", "add", "sub", "mul", "sdiv", "and", "or", "xor",
];
let pred_types = ["nxv4i1", "nxv2i1", "nxv8i1"];
let vec_types = ["nxv4i32", "nxv2i64", "nxv8i16", "nxv4f32", "nxv2f64"];
for op in &sve_ops {
for vt in &vec_types {
for pt in &pred_types {
result.push(IntrinsicDesc2 {
name: format!("llvm.aarch64.sve.{}.{}.{}", op, vt, pt),
return_type: vt.to_string(),
param_types: vec![vt.to_string(), vt.to_string(), pt.to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec!["aarch64".to_string()],
category: IntrinsicCategory2::VectorPredication,
});
}
}
}
result
}
pub fn riscv_vector_intrinsics() -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
let rvv_ops = [
"vadd",
"vsub",
"vmul",
"vdiv",
"vand",
"vor",
"vxor",
"vfadd",
"vfsub",
"vfmul",
"vfdiv",
"vle",
"vse",
"vlse",
"vsse",
"vrgather",
"vcompress",
"vmerge",
"vredsum",
"vredmax",
"vredmin",
];
let lmul_variants = ["v", "v2", "v4", "v8"];
for op in &rvv_ops {
for lmul in &lmul_variants {
result.push(IntrinsicDesc2 {
name: format!("llvm.riscv.{}.{}.i32.{}", op, lmul, lmul),
return_type: format!("<{} x i32>", lmul),
param_types: vec![
format!("<{} x i32>", lmul),
format!("<{} x i32>", lmul),
"i64".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec!["riscv64".to_string()],
category: IntrinsicCategory2::VectorPredication,
});
}
}
result
}
pub fn wasm_simd_intrinsics() -> Vec<IntrinsicDesc2> {
vec![
IntrinsicDesc2 {
name: "llvm.wasm.swizzle".to_string(),
return_type: "<16 x i8>".to_string(),
param_types: vec!["<16 x i8>".to_string(), "<16 x i8>".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec!["wasm32".to_string()],
category: IntrinsicCategory2::VectorPredication,
},
IntrinsicDesc2 {
name: "llvm.wasm.bitselect".to_string(),
return_type: "<4 x i32>".to_string(),
param_types: vec![
"<4 x i32>".to_string(),
"<4 x i32>".to_string(),
"<4 x i32>".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec!["wasm32".to_string()],
category: IntrinsicCategory2::VectorPredication,
},
IntrinsicDesc2 {
name: "llvm.wasm.avgr.unsigned".to_string(),
return_type: "<16 x i8>".to_string(),
param_types: vec!["<16 x i8>".to_string(), "<16 x i8>".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec!["wasm32".to_string()],
category: IntrinsicCategory2::VectorPredication,
},
IntrinsicDesc2 {
name: "llvm.wasm.narrow.signed".to_string(),
return_type: "<8 x i16>".to_string(),
param_types: vec!["<4 x i32>".to_string(), "<4 x i32>".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec!["wasm32".to_string()],
category: IntrinsicCategory2::VectorPredication,
},
IntrinsicDesc2 {
name: "llvm.wasm.extend.high.signed".to_string(),
return_type: "<4 x i32>".to_string(),
param_types: vec!["<8 x i16>".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec!["wasm32".to_string()],
category: IntrinsicCategory2::VectorPredication,
},
IntrinsicDesc2 {
name: "llvm.wasm.trunc.saturate.signed".to_string(),
return_type: "<4 x i32>".to_string(),
param_types: vec!["<4 x f32>".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec!["wasm32".to_string()],
category: IntrinsicCategory2::VectorPredication,
},
IntrinsicDesc2 {
name: "llvm.wasm.dot".to_string(),
return_type: "<4 x i32>".to_string(),
param_types: vec!["<8 x i16>".to_string(), "<8 x i16>".to_string()],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec!["wasm32".to_string()],
category: IntrinsicCategory2::VectorPredication,
},
IntrinsicDesc2 {
name: "llvm.wasm.shuffle".to_string(),
return_type: "<16 x i8>".to_string(),
param_types: vec![
"<16 x i8>".to_string(),
"<16 x i8>".to_string(),
"<16 x i8>".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
],
targets: vec!["wasm32".to_string()],
category: IntrinsicCategory2::VectorPredication,
},
]
}
pub fn elementwise_atomic_intrinsics() -> Vec<IntrinsicDesc2> {
let mut result = Vec::new();
let ops = [
"add", "sub", "and", "or", "xor", "xchg", "max", "min", "umax", "umin",
];
let types = ["i8", "i16", "i32", "i64"];
for op in &ops {
for ty in &types {
result.push(IntrinsicDesc2 {
name: format!("llvm.memcpy.element.unordered.atomic.{}.{}", op, ty),
return_type: "void".to_string(),
param_types: vec![
"ptr".to_string(),
"ptr".to_string(),
"i64".to_string(),
"i32".to_string(),
],
attributes: vec![
IntrinsicAttribute2::NoUnwind,
IntrinsicAttribute2::WillReturn,
IntrinsicAttribute2::ArgMemOnly,
],
targets: vec![],
category: IntrinsicCategory2::VectorPredication,
});
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_matrix_intrinsics() {
let intrinsics = all_matrix_intrinsics();
assert!(intrinsics.len() > 20);
let has_multiply = intrinsics.iter().any(|i| i.name.contains("multiply"));
assert!(has_multiply);
let has_transpose = intrinsics.iter().any(|i| i.name.contains("transpose"));
assert!(has_transpose);
let has_load = intrinsics
.iter()
.any(|i| i.name.contains("column.major.load"));
assert!(has_load);
let has_store = intrinsics
.iter()
.any(|i| i.name.contains("column.major.store"));
assert!(has_store);
}
#[test]
fn test_vp_intrinsics() {
let vp = all_vp_intrinsics();
assert!(vp.len() > 50);
let has_add = vp.iter().any(|i| i.name.starts_with("llvm.vp.add"));
assert!(has_add);
let has_load = vp.iter().any(|i| i.name.starts_with("llvm.vp.load"));
assert!(has_load);
let has_store = vp.iter().any(|i| i.name.starts_with("llvm.vp.store"));
assert!(has_store);
let has_gather = vp.iter().any(|i| i.name.starts_with("llvm.vp.gather"));
assert!(has_gather);
let has_reduce = vp.iter().any(|i| i.name.starts_with("llvm.vp.reduce"));
assert!(has_reduce);
let has_merge = vp.iter().any(|i| i.name.starts_with("llvm.vp.merge"));
assert!(has_merge);
let has_select = vp.iter().any(|i| i.name.starts_with("llvm.vp.select"));
assert!(has_select);
}
#[test]
fn test_constrained_fp_intrinsics() {
let cfp = all_constrained_fp_intrinsics();
assert!(cfp.len() > 30);
let has_fadd = cfp.iter().any(|i| i.name.contains("fadd"));
assert!(has_fadd);
let has_sqrt = cfp.iter().any(|i| i.name.contains("sqrt"));
assert!(has_sqrt);
let has_pow = cfp.iter().any(|i| i.name.contains("pow"));
assert!(has_pow);
}
#[test]
fn test_hardware_loop_intrinsics() {
let hw = hardware_loop_intrinsics();
assert!(hw.len() >= 3);
let has_set_iter = hw.iter().any(|i| i.name.contains("set.loop.iterations"));
assert!(has_set_iter);
let has_decrement = hw.iter().any(|i| i.name.contains("loop.decrement"));
assert!(has_decrement);
}
#[test]
fn test_stackmap_intrinsics() {
let sm = stackmap_intrinsics();
assert!(sm.len() >= 3);
let has_stackmap = sm.iter().any(|i| i.name.contains("stackmap"));
assert!(has_stackmap);
let has_patchpoint = sm.iter().any(|i| i.name.contains("patchpoint"));
assert!(has_patchpoint);
let has_statepoint = sm.iter().any(|i| i.name.contains("statepoint"));
assert!(has_statepoint);
}
#[test]
fn test_gc_relocation_intrinsics() {
let gc = gc_relocation_intrinsics();
assert!(gc.len() >= 2);
let has_result = gc.iter().any(|i| i.name.contains("gc.result"));
assert!(has_result);
let has_relocate = gc.iter().any(|i| i.name.contains("gc.relocate"));
assert!(has_relocate);
}
#[test]
fn test_assume_bundles() {
let assume = assume_bundle_intrinsics();
assert!(assume.len() >= 4);
}
#[test]
fn test_debug_info_extended() {
let dbg = debug_info_intrinsics_extended();
assert!(!dbg.is_empty());
let has_addr = dbg.iter().any(|i| i.name.contains("dbg.addr"));
assert!(has_addr);
let has_assign = dbg.iter().any(|i| i.name.contains("dbg.assign"));
assert!(has_assign);
}
#[test]
fn test_objc_arc_intrinsics() {
let arc = objc_arc_intrinsics();
assert!(arc.len() >= 6);
let has_retain = arc.iter().any(|i| i.name.contains("objc.retain"));
assert!(has_retain);
let has_release = arc.iter().any(|i| i.name.contains("objc.release"));
assert!(has_release);
}
#[test]
fn test_pointer_auth_intrinsics() {
let pa = pointer_auth_intrinsics();
assert!(pa.len() >= 5);
let has_sign = pa.iter().any(|i| i.name.contains("ptrauth.sign"));
assert!(has_sign);
let has_auth = pa.iter().any(|i| i.name.contains("ptrauth.auth"));
assert!(has_auth);
}
#[test]
fn test_convergence_intrinsics() {
let cc = convergence_control_intrinsics();
assert!(cc.len() >= 3);
}
#[test]
fn test_database_creation() {
let db = IntrinsicDatabase2::new();
assert!(db.total_count() > 100);
}
#[test]
fn test_database_find_by_name() {
let db = IntrinsicDatabase2::new();
let found = db.find_by_name("llvm.objc.retain");
assert!(found.is_some());
assert_eq!(found.unwrap().category, IntrinsicCategory2::ObjCARC);
}
#[test]
fn test_database_find_by_prefix() {
let db = IntrinsicDatabase2::new();
let results = db.find_by_prefix("llvm.ptrauth");
assert!(results.len() >= 3);
}
#[test]
fn test_database_find_by_category() {
let db = IntrinsicDatabase2::new();
let results = db.find_by_category(IntrinsicCategory2::PointerAuth);
assert!(results.len() >= 4);
}
#[test]
fn test_extended_coroutine_intrinsics() {
let coros = extended_coroutine_intrinsics();
assert!(coros.len() >= 2);
let has_suspend = coros.iter().any(|i| i.name.contains("suspend"));
assert!(has_suspend);
}
#[test]
fn test_aarch64_sve_vp_intrinsics() {
let sve = aarch64_sve_vp_intrinsics();
assert!(sve.len() >= 50);
let has_fadd = sve.iter().any(|i| i.name.contains("fadd"));
assert!(has_fadd);
let all_aarch64 = sve
.iter()
.all(|i| i.targets.contains(&"aarch64".to_string()));
assert!(all_aarch64);
}
#[test]
fn test_riscv_vector_intrinsics() {
let rvv = riscv_vector_intrinsics();
assert!(rvv.len() >= 30);
let has_vadd = rvv.iter().any(|i| i.name.contains("vadd"));
assert!(has_vadd);
}
#[test]
fn test_wasm_simd_intrinsics() {
let wasm = wasm_simd_intrinsics();
assert!(wasm.len() >= 5);
let has_swizzle = wasm.iter().any(|i| i.name.contains("swizzle"));
assert!(has_swizzle);
}
#[test]
fn test_elementwise_atomic_intrinsics() {
let atomics = elementwise_atomic_intrinsics();
assert!(atomics.len() >= 20);
let has_add = atomics.iter().any(|i| i.name.contains("add"));
assert!(has_add);
}
}