#[allow(unused_imports)]
use crate::clang::ast::*;
#[allow(unused_imports)]
use crate::clang::sema::*;
#[allow(unused_imports)]
use crate::x86::*;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(u8)]
pub enum CompletionKind {
Function = 1,
Variable = 2,
Type = 3,
Macro = 4,
Keyword = 5,
Directive = 6,
Field = 7,
EnumMember = 8,
Namespace = 9,
Snippet = 10,
File = 11,
Label = 12,
Concept = 13,
Operator = 14,
TypeParameter = 15,
Intrinsic = 16,
Module = 17,
Constant = 18,
}
impl CompletionKind {
pub fn icon(&self) -> &'static str {
match self {
Self::Function => "f",
Self::Variable => "v",
Self::Type => "t",
Self::Macro => "m",
Self::Keyword => "k",
Self::Directive => "#",
Self::Field => ".",
Self::EnumMember => "e",
Self::Namespace => "n",
Self::Snippet => "~",
Self::File => "F",
Self::Label => "l",
Self::Concept => "c",
Self::Operator => "o",
Self::TypeParameter => "p",
Self::Intrinsic => "i",
Self::Module => "M",
Self::Constant => "C",
}
}
pub fn lsp_kind(&self) -> u32 {
match self {
Self::Function => 3,
Self::Variable => 6,
Self::Type => 7,
Self::Macro => 1,
Self::Keyword => 14,
Self::Directive => 1,
Self::Field => 5,
Self::EnumMember => 13,
Self::Namespace => 8,
Self::Snippet => 15,
Self::File => 17,
Self::Label => 5,
Self::Concept => 8,
Self::Operator => 11,
Self::TypeParameter => 25,
Self::Intrinsic => 3,
Self::Module => 9,
Self::Constant => 21,
}
}
}
impl fmt::Display for CompletionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Self::Function => "function",
Self::Variable => "variable",
Self::Type => "type",
Self::Macro => "macro",
Self::Keyword => "keyword",
Self::Directive => "directive",
Self::Field => "field",
Self::EnumMember => "enum",
Self::Namespace => "namespace",
Self::Snippet => "snippet",
Self::File => "file",
Self::Label => "label",
Self::Concept => "concept",
Self::Operator => "operator",
Self::TypeParameter => "type-param",
Self::Intrinsic => "intrinsic",
Self::Module => "module",
Self::Constant => "constant",
};
write!(f, "{}", s)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CompletionContext {
DotAccess { receiver_type: Option<String> },
ArrowAccess { receiver_type: Option<String> },
ScopeResolution { scope_name: Option<String> },
OpenParen { callee: Option<String> },
TypeName,
Declaration,
Directive,
IncludeQuote { partial: String },
IncludeAngle { partial: String },
General,
Statement,
Return,
Case,
Goto,
}
impl CompletionContext {
pub fn from_source_line(line: &str, column: usize) -> Self {
let prefix = if column <= line.len() {
&line[..column]
} else {
line
};
let trimmed = prefix.trim();
if let Some(quote_pos) = trimmed.rfind("#include \"") {
let partial = trimmed[quote_pos + 10..].to_string();
return Self::IncludeQuote { partial };
}
if let Some(angle_pos) = trimmed.rfind("#include <") {
let partial = trimmed[angle_pos + 10..].to_string();
return Self::IncludeAngle { partial };
}
if trimmed.ends_with('#') || trimmed == "#" {
return Self::Directive;
}
if trimmed.starts_with('#')
&& !trimmed.starts_with("#include")
&& !trimmed.starts_with("#define")
&& !trimmed.starts_with("#if")
&& !trimmed.starts_with("#endif")
&& !trimmed.starts_with("#else")
&& !trimmed.starts_with("#elif")
&& !trimmed.starts_with("#pragma")
&& !trimmed.starts_with("#error")
&& !trimmed.starts_with("#warning")
&& !trimmed.starts_with("#undef")
&& !trimmed.starts_with("#line")
{
return Self::Directive;
}
if trimmed.ends_with("::") {
let scope_part = &trimmed[..trimmed.len() - 2];
let scope_name = scope_part
.rsplit(|c: char| !c.is_alphanumeric() && c != '_' && c != ':')
.next()
.map(|s| s.to_string());
return Self::ScopeResolution { scope_name };
}
if trimmed.ends_with('.') {
return Self::DotAccess {
receiver_type: extract_receiver(trimmed),
};
}
if trimmed.ends_with("->") {
return Self::ArrowAccess {
receiver_type: extract_receiver(trimmed),
};
}
if trimmed.ends_with('(') {
return Self::OpenParen {
callee: extract_callee(trimmed),
};
}
let last_word = trimmed
.rsplit(|c: char| c.is_whitespace())
.next()
.unwrap_or("");
match last_word {
"return" => return Self::Return,
"case" => return Self::Case,
"goto" => return Self::Goto,
_ => {}
}
let type_kws = [
"int", "long", "short", "char", "float", "double", "void", "unsigned", "signed",
"struct", "enum", "union", "class", "const", "volatile", "static", "extern", "typedef",
"auto", "register", "_Bool", "_Complex",
];
for kw in &type_kws {
if trimmed.ends_with(&format!("{} ", kw)) || trimmed.ends_with(&format!("{}\t", kw)) {
return Self::TypeName;
}
}
if trimmed.is_empty() {
return Self::General;
}
if trimmed.ends_with(';') || trimmed.ends_with('{') || trimmed.ends_with('}') {
return Self::Declaration;
}
let stmt_kws = ["if", "for", "while", "do", "switch"];
for kw in &stmt_kws {
if trimmed.ends_with(&format!("{} ", kw)) || trimmed.ends_with(&format!("{}\t", kw)) {
return Self::Statement;
}
}
Self::General
}
}
fn extract_receiver(text: &str) -> Option<String> {
let stripped = if text.ends_with("->") {
&text[..text.len() - 2]
} else {
&text[..text.len() - 1]
};
let ident = stripped
.rsplit(|c: char| !c.is_alphanumeric() && c != '_')
.next()?;
if ident.is_empty() {
None
} else {
Some(ident.to_string())
}
}
fn extract_callee(text: &str) -> Option<String> {
let before = &text[..text.len() - 1];
let ident = before
.rsplit(|c: char| !c.is_alphanumeric() && c != '_' && c != ':')
.next()?;
if ident.is_empty()
|| ident == "if"
|| ident == "for"
|| ident == "while"
|| ident == "switch"
|| ident == "return"
|| ident == "sizeof"
{
None
} else {
Some(ident.to_string())
}
}
#[derive(Debug, Clone)]
pub struct CompletionResult {
pub display_text: String,
pub insert_text: String,
pub kind: CompletionKind,
pub priority: i32,
pub documentation: Option<String>,
pub detail: Option<String>,
pub additional_edits: Vec<AdditionalEdit>,
pub deprecated: bool,
pub is_snippet: bool,
pub sort_text: Option<String>,
pub filter_text: Option<String>,
}
#[derive(Debug, Clone)]
pub struct AdditionalEdit {
pub file: Option<String>,
pub line: usize,
pub column: usize,
pub new_text: String,
}
impl CompletionResult {
pub fn keyword(name: &str) -> Self {
Self {
display_text: name.to_string(),
insert_text: name.to_string(),
kind: CompletionKind::Keyword,
priority: 100,
documentation: Some(format!("Keyword: `{}`", name)),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
}
}
pub fn macro_(name: &str, doc: Option<&str>) -> Self {
Self {
display_text: name.to_string(),
insert_text: name.to_string(),
kind: CompletionKind::Macro,
priority: 90,
documentation: doc.map(|d| d.to_string()),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
}
}
pub fn directive(name: &str, doc: &str) -> Self {
Self {
display_text: name.to_string(),
insert_text: format!("{} ", name),
kind: CompletionKind::Directive,
priority: 95,
documentation: Some(doc.to_string()),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
}
}
pub fn intrinsic(name: &str, params: &[(&str, &str)], ret: &str, header: &str) -> Self {
let param_str: Vec<String> = params
.iter()
.map(|(ptype, pname)| format!("{} {}", ptype, pname))
.collect();
let detail_text = format!(
"{} {}({}) — header: <{}>",
ret,
name,
param_str.join(", "),
header
);
Self {
display_text: format!("{} {}", ret, name),
insert_text: format!("{}(", name),
kind: CompletionKind::Intrinsic,
priority: 85,
documentation: Some(detail_text.clone()),
detail: Some(detail_text),
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: Some(name.to_string()),
}
}
pub fn snippet(label: &str, insert: &str, doc: &str) -> Self {
Self {
display_text: label.to_string(),
insert_text: insert.to_string(),
kind: CompletionKind::Snippet,
priority: 50,
documentation: Some(doc.to_string()),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: true,
sort_text: None,
filter_text: None,
}
}
pub fn type_(name: &str, doc: Option<&str>) -> Self {
Self {
display_text: name.to_string(),
insert_text: name.to_string(),
kind: CompletionKind::Type,
priority: 80,
documentation: doc.map(|d| d.to_string()),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
}
}
pub fn file(path: &str) -> Self {
Self {
display_text: path.to_string(),
insert_text: path.to_string(),
kind: CompletionKind::File,
priority: 70,
documentation: None,
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
}
}
pub fn with_sort_text(mut self, sort: &str) -> Self {
self.sort_text = Some(sort.to_string());
self
}
pub fn with_filter_text(mut self, filter: &str) -> Self {
self.filter_text = Some(filter.to_string());
self
}
pub fn with_priority(mut self, priority: i32) -> Self {
self.priority = priority;
self
}
pub fn deprecated(mut self) -> Self {
self.deprecated = true;
self
}
}
impl fmt::Display for CompletionResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} {} | {}",
self.kind.icon(),
self.display_text,
self.kind
)
}
}
pub struct X86CompletionDatabase {
pub c_keywords: Vec<CompletionResult>,
pub cxx_keywords: Vec<CompletionResult>,
pub x86_keywords: Vec<CompletionResult>,
pub directives: Vec<CompletionResult>,
pub builtin_macros: Vec<CompletionResult>,
pub operators: Vec<CompletionResult>,
pub generic_macros: Vec<CompletionResult>,
}
impl Default for X86CompletionDatabase {
fn default() -> Self {
Self::new()
}
}
impl X86CompletionDatabase {
pub fn new() -> Self {
Self {
c_keywords: build_c_keywords(),
cxx_keywords: build_cxx_keywords(),
x86_keywords: build_x86_keywords(),
directives: build_directives(),
builtin_macros: build_builtin_macros(),
operators: build_operator_completions(),
generic_macros: build_generic_macros(),
}
}
pub fn query_keywords(&self, prefix: &str, cxx_mode: bool) -> Vec<CompletionResult> {
let mut r = Vec::new();
let lower = prefix.to_lowercase();
for kw in &self.c_keywords {
if kw
.filter_text
.as_ref()
.unwrap_or(&kw.display_text)
.to_lowercase()
.starts_with(&lower)
{
r.push(kw.clone());
}
}
if cxx_mode {
for kw in &self.cxx_keywords {
if kw
.filter_text
.as_ref()
.unwrap_or(&kw.display_text)
.to_lowercase()
.starts_with(&lower)
{
r.push(kw.clone());
}
}
}
for kw in &self.x86_keywords {
if kw
.filter_text
.as_ref()
.unwrap_or(&kw.display_text)
.to_lowercase()
.starts_with(&lower)
{
r.push(kw.clone());
}
}
r.sort_by_key(|k| -k.priority);
r
}
pub fn query_directives(&self, prefix: &str) -> Vec<CompletionResult> {
let lower = prefix.to_lowercase();
self.directives
.iter()
.filter(|d| {
d.filter_text
.as_ref()
.unwrap_or(&d.display_text)
.to_lowercase()
.starts_with(&lower)
})
.cloned()
.collect()
}
pub fn query_builtin_macros(&self, prefix: &str) -> Vec<CompletionResult> {
let lower = prefix.to_lowercase();
self.builtin_macros
.iter()
.filter(|m| {
m.filter_text
.as_ref()
.unwrap_or(&m.display_text)
.to_lowercase()
.starts_with(&lower)
})
.cloned()
.collect()
}
pub fn all_general_completions(&self, cxx_mode: bool) -> Vec<CompletionResult> {
let mut r = Vec::new();
r.extend(self.c_keywords.iter().cloned());
if cxx_mode {
r.extend(self.cxx_keywords.iter().cloned());
}
r.extend(self.x86_keywords.iter().cloned());
r.extend(self.builtin_macros.iter().cloned());
r.extend(self.generic_macros.iter().cloned());
r
}
}
fn build_c_keywords() -> Vec<CompletionResult> {
vec![
CompletionResult::keyword("auto"),
CompletionResult::keyword("break"),
CompletionResult::keyword("case"),
CompletionResult::keyword("char"),
CompletionResult::keyword("const"),
CompletionResult::keyword("continue"),
CompletionResult::keyword("default"),
CompletionResult::keyword("do"),
CompletionResult::keyword("double"),
CompletionResult::keyword("else"),
CompletionResult::keyword("enum").with_priority(110),
CompletionResult::keyword("extern"),
CompletionResult::keyword("float"),
CompletionResult::keyword("for").with_priority(110),
CompletionResult::keyword("goto"),
CompletionResult::keyword("if").with_priority(110),
CompletionResult::keyword("inline"),
CompletionResult::keyword("int"),
CompletionResult::keyword("long"),
CompletionResult::keyword("register"),
CompletionResult::keyword("restrict"),
CompletionResult::keyword("return").with_priority(110),
CompletionResult::keyword("short"),
CompletionResult::keyword("signed"),
CompletionResult::keyword("sizeof").with_priority(105),
CompletionResult::keyword("static"),
CompletionResult::keyword("struct").with_priority(110),
CompletionResult::keyword("switch").with_priority(110),
CompletionResult::keyword("typedef"),
CompletionResult::keyword("union"),
CompletionResult::keyword("unsigned"),
CompletionResult::keyword("void"),
CompletionResult::keyword("volatile"),
CompletionResult::keyword("while").with_priority(110),
CompletionResult::keyword("_Bool"),
CompletionResult::keyword("_Complex"),
CompletionResult::keyword("_Imaginary").deprecated(),
CompletionResult::keyword("_Alignas"),
CompletionResult::keyword("_Alignof"),
CompletionResult::keyword("_Atomic"),
CompletionResult::keyword("_Generic").with_priority(105),
CompletionResult::keyword("_Noreturn"),
CompletionResult::keyword("_Static_assert"),
CompletionResult::keyword("_Thread_local"),
]
}
fn build_cxx_keywords() -> Vec<CompletionResult> {
vec![
CompletionResult::keyword("alignas"),
CompletionResult::keyword("alignof"),
CompletionResult::keyword("and"),
CompletionResult::keyword("and_eq"),
CompletionResult::keyword("asm"),
CompletionResult::keyword("bitand"),
CompletionResult::keyword("bitor"),
CompletionResult::keyword("bool"),
CompletionResult::keyword("catch").with_priority(110),
CompletionResult::keyword("char8_t"),
CompletionResult::keyword("char16_t"),
CompletionResult::keyword("char32_t"),
CompletionResult::keyword("class").with_priority(115),
CompletionResult::keyword("compl"),
CompletionResult::keyword("concept").with_priority(110),
CompletionResult::keyword("const_cast"),
CompletionResult::keyword("consteval"),
CompletionResult::keyword("constexpr"),
CompletionResult::keyword("constinit"),
CompletionResult::keyword("co_await"),
CompletionResult::keyword("co_return"),
CompletionResult::keyword("co_yield"),
CompletionResult::keyword("decltype").with_priority(105),
CompletionResult::keyword("delete"),
CompletionResult::keyword("dynamic_cast"),
CompletionResult::keyword("explicit"),
CompletionResult::keyword("export"),
CompletionResult::keyword("false"),
CompletionResult::keyword("final"),
CompletionResult::keyword("friend"),
CompletionResult::keyword("mutable"),
CompletionResult::keyword("namespace").with_priority(110),
CompletionResult::keyword("new"),
CompletionResult::keyword("noexcept"),
CompletionResult::keyword("not"),
CompletionResult::keyword("not_eq"),
CompletionResult::keyword("nullptr"),
CompletionResult::keyword("operator"),
CompletionResult::keyword("or"),
CompletionResult::keyword("or_eq"),
CompletionResult::keyword("override"),
CompletionResult::keyword("private"),
CompletionResult::keyword("protected"),
CompletionResult::keyword("public"),
CompletionResult::keyword("reinterpret_cast"),
CompletionResult::keyword("requires").with_priority(105),
CompletionResult::keyword("static_cast"),
CompletionResult::keyword("template").with_priority(110),
CompletionResult::keyword("this"),
CompletionResult::keyword("thread_local"),
CompletionResult::keyword("throw"),
CompletionResult::keyword("true"),
CompletionResult::keyword("try").with_priority(110),
CompletionResult::keyword("typeid"),
CompletionResult::keyword("typename"),
CompletionResult::keyword("using"),
CompletionResult::keyword("virtual"),
CompletionResult::keyword("wchar_t"),
CompletionResult::keyword("xor"),
CompletionResult::keyword("xor_eq"),
]
}
fn build_x86_keywords() -> Vec<CompletionResult> {
vec![
CompletionResult::keyword("__asm__").with_priority(95),
CompletionResult::keyword("__attribute__").with_priority(95),
CompletionResult::keyword("__declspec").with_priority(90),
CompletionResult::keyword("__builtin_choose_expr").with_priority(85),
CompletionResult::keyword("__builtin_constant_p").with_priority(85),
CompletionResult::keyword("__builtin_expect").with_priority(85),
CompletionResult::keyword("__builtin_prefetch").with_priority(85),
CompletionResult::keyword("__builtin_types_compatible_p").with_priority(85),
CompletionResult::keyword("__builtin_va_arg"),
CompletionResult::keyword("__builtin_va_copy"),
CompletionResult::keyword("__builtin_va_end"),
CompletionResult::keyword("__builtin_va_start"),
CompletionResult::keyword("__builtin_alloca"),
CompletionResult::keyword("__builtin_bswap16"),
CompletionResult::keyword("__builtin_bswap32"),
CompletionResult::keyword("__builtin_bswap64"),
CompletionResult::keyword("__builtin_clz"),
CompletionResult::keyword("__builtin_clzl"),
CompletionResult::keyword("__builtin_clzll"),
CompletionResult::keyword("__builtin_ctz"),
CompletionResult::keyword("__builtin_ctzl"),
CompletionResult::keyword("__builtin_ctzll"),
CompletionResult::keyword("__builtin_popcount"),
CompletionResult::keyword("__builtin_popcountl"),
CompletionResult::keyword("__builtin_popcountll"),
CompletionResult::keyword("__builtin_parity"),
CompletionResult::keyword("__builtin_ffs"),
CompletionResult::keyword("__builtin_ffsl"),
CompletionResult::keyword("__builtin_ffsll"),
CompletionResult::keyword("__builtin_unreachable"),
CompletionResult::keyword("__builtin_trap"),
CompletionResult::keyword("__builtin___clear_cache"),
CompletionResult::keyword("__builtin___memset_chk"),
CompletionResult::keyword("__builtin___memcpy_chk"),
CompletionResult::keyword("__builtin_object_size"),
CompletionResult::keyword("__builtin_return_address"),
CompletionResult::keyword("__builtin_frame_address"),
CompletionResult::keyword("__builtin_extract_return_addr"),
CompletionResult::keyword("__builtin_fabs"),
CompletionResult::keyword("__builtin_fabsf"),
CompletionResult::keyword("__builtin_fabsl"),
CompletionResult::keyword("__builtin_copysign"),
CompletionResult::keyword("__builtin_copysignf"),
CompletionResult::keyword("__builtin_copysignl"),
CompletionResult::keyword("__builtin_inf"),
CompletionResult::keyword("__builtin_inff"),
CompletionResult::keyword("__builtin_infl"),
CompletionResult::keyword("__builtin_nan"),
CompletionResult::keyword("__builtin_nanf"),
CompletionResult::keyword("__builtin_nanl"),
CompletionResult::keyword("__builtin_huge_val"),
CompletionResult::keyword("__builtin_huge_valf"),
CompletionResult::keyword("__builtin_huge_vall"),
CompletionResult::keyword("__builtin_isgreater"),
CompletionResult::keyword("__builtin_isgreaterequal"),
CompletionResult::keyword("__builtin_isless"),
CompletionResult::keyword("__builtin_islessequal"),
CompletionResult::keyword("__builtin_islessgreater"),
CompletionResult::keyword("__builtin_isunordered"),
CompletionResult::keyword("__builtin_isfinite"),
CompletionResult::keyword("__builtin_isinf"),
CompletionResult::keyword("__builtin_isinf_sign"),
CompletionResult::keyword("__builtin_isnan"),
CompletionResult::keyword("__builtin_isnormal"),
CompletionResult::keyword("__builtin_signbit"),
CompletionResult::keyword("__vector_size__").with_priority(85),
CompletionResult::keyword("__mode__").with_priority(80),
CompletionResult::keyword("__alignof__").with_priority(85),
CompletionResult::keyword("__typeof__").with_priority(85),
CompletionResult::keyword("__extension__").with_priority(80),
CompletionResult::keyword("__int128").with_priority(75),
CompletionResult::keyword("__uint128").with_priority(75),
CompletionResult::keyword("__float80").with_priority(75),
CompletionResult::keyword("__float128").with_priority(75),
CompletionResult::keyword("__m64").with_priority(80),
CompletionResult::keyword("__m128").with_priority(80),
CompletionResult::keyword("__m128d").with_priority(80),
CompletionResult::keyword("__m128i").with_priority(80),
CompletionResult::keyword("__m256").with_priority(80),
CompletionResult::keyword("__m256d").with_priority(80),
CompletionResult::keyword("__m256i").with_priority(80),
CompletionResult::keyword("__m512").with_priority(80),
CompletionResult::keyword("__m512d").with_priority(80),
CompletionResult::keyword("__m512i").with_priority(80),
CompletionResult::keyword("__mmask8").with_priority(80),
CompletionResult::keyword("__mmask16").with_priority(80),
CompletionResult::keyword("__mmask32").with_priority(80),
CompletionResult::keyword("__mmask64").with_priority(80),
CompletionResult::keyword("__builtin_cpu_supports").with_priority(85),
CompletionResult::keyword("__builtin_cpu_is").with_priority(85),
CompletionResult::keyword("__builtin_cpu_init").with_priority(85),
]
}
fn build_directives() -> Vec<CompletionResult> {
vec![
CompletionResult::directive("#include", "Include a header file"),
CompletionResult::directive("#define", "Define a preprocessor macro"),
CompletionResult::directive("#undef", "Undefine a preprocessor macro"),
CompletionResult::directive("#if", "Conditional compilation: if"),
CompletionResult::directive("#ifdef", "Conditional compilation: if defined"),
CompletionResult::directive("#ifndef", "Conditional compilation: if not defined"),
CompletionResult::directive("#elif", "Conditional compilation: else-if"),
CompletionResult::directive("#else", "Conditional compilation: else"),
CompletionResult::directive("#endif", "End conditional compilation block"),
CompletionResult::directive("#pragma", "Compiler-specific pragma directive"),
CompletionResult::directive("#error", "Emit a compilation error message"),
CompletionResult::directive("#warning", "Emit a compilation warning message"),
CompletionResult::directive("#line", "Set the current line number and file name"),
CompletionResult::directive("#pragma once", "Ensure header is included only once"),
CompletionResult::directive(
"#pragma GCC diagnostic",
"Control GCC/Clang diagnostic messages",
),
CompletionResult::directive(
"#pragma GCC optimize",
"Set optimization level for a function",
),
CompletionResult::directive(
"#pragma GCC target",
"Set target-specific options for a function",
),
CompletionResult::directive("#pragma message", "Emit a compiler informational message"),
CompletionResult::directive("#pragma pack", "Control structure packing alignment"),
CompletionResult::directive("#pragma clang loop", "Control loop optimization hints"),
CompletionResult::directive("#pragma omp", "OpenMP directive"),
CompletionResult::directive("#pragma omp parallel", "OpenMP: parallel region"),
CompletionResult::directive("#pragma omp simd", "OpenMP: SIMD loop vectorization"),
]
}
fn build_builtin_macros() -> Vec<CompletionResult> {
vec![
CompletionResult::macro_("__FILE__", Some("Current source file name")),
CompletionResult::macro_("__LINE__", Some("Current source line number")),
CompletionResult::macro_("__DATE__", Some("Compilation date")),
CompletionResult::macro_("__TIME__", Some("Compilation time")),
CompletionResult::macro_("__STDC__", Some("Defined to 1 for standard C")),
CompletionResult::macro_("__STDC_VERSION__", Some("C standard version")),
CompletionResult::macro_("__STDC_HOSTED__", Some("1 for hosted implementation")),
CompletionResult::macro_("__cplusplus", Some("C++ standard version")),
CompletionResult::macro_("__OBJC__", Some("Defined to 1 for Objective-C")),
CompletionResult::macro_(
"__ASSEMBLER__",
Some("Defined to 1 when preprocessing assembly"),
),
CompletionResult::macro_("__GNUC__", Some("GCC major version")),
CompletionResult::macro_("__GNUC_MINOR__", Some("GCC minor version")),
CompletionResult::macro_("__GNUC_PATCHLEVEL__", Some("GCC patch level")),
CompletionResult::macro_("__clang__", Some("Defined to 1 for Clang")),
CompletionResult::macro_("__clang_major__", Some("Clang major version")),
CompletionResult::macro_("__clang_minor__", Some("Clang minor version")),
CompletionResult::macro_("__clang_patchlevel__", Some("Clang patch level")),
CompletionResult::macro_("__llvm__", Some("Defined to 1 for LLVM/Clang compiler")),
CompletionResult::macro_("__VERSION__", Some("Compiler version string")),
CompletionResult::macro_("__BASE_FILE__", Some("Main input file name")),
CompletionResult::macro_("__FILE_NAME__", Some("Current file base name (no path)")),
CompletionResult::macro_("__TIMESTAMP__", Some("File modification timestamp")),
CompletionResult::macro_("__COUNTER__", Some("Incrementing integer counter")),
CompletionResult::macro_("__INCLUDE_LEVEL__", Some("Current include nesting depth")),
CompletionResult::macro_("__has_include", Some("Check if header is available")),
CompletionResult::macro_(
"__has_include_next",
Some("Check if header is available (next)"),
),
CompletionResult::macro_(
"__has_builtin",
Some("Check if builtin function is available"),
),
CompletionResult::macro_(
"__has_feature",
Some("Check if language feature is available"),
),
CompletionResult::macro_(
"__has_extension",
Some("Check if language extension is available"),
),
CompletionResult::macro_("__has_attribute", Some("Check if attribute is supported")),
CompletionResult::macro_(
"__has_cpp_attribute",
Some("Check if C++ attribute is supported"),
),
CompletionResult::macro_(
"__has_declspec_attribute",
Some("Check if __declspec attribute is supported"),
),
CompletionResult::macro_("__PRETTY_FUNCTION__", Some("Pretty function name")),
CompletionResult::macro_("__FUNCTION__", Some("Function name")),
CompletionResult::macro_("__func__", Some("Function name (C99)")),
CompletionResult::macro_("__x86_64__", Some("Defined for x86-64 targets")),
CompletionResult::macro_("__x86_64", Some("Defined for x86-64 targets")),
CompletionResult::macro_("__amd64__", Some("Defined for AMD64 targets")),
CompletionResult::macro_("__amd64", Some("Defined for AMD64 targets")),
CompletionResult::macro_("__i386__", Some("Defined for IA-32 targets")),
CompletionResult::macro_("__i386", Some("Defined for IA-32 targets")),
CompletionResult::macro_("__i686__", Some("Defined for i686+ targets")),
CompletionResult::macro_("__i686", Some("Defined for i686+ targets")),
CompletionResult::macro_("__SSE__", Some("SSE enabled")),
CompletionResult::macro_("__SSE2__", Some("SSE2 enabled")),
CompletionResult::macro_("__SSE3__", Some("SSE3 enabled")),
CompletionResult::macro_("__SSSE3__", Some("SSSE3 enabled")),
CompletionResult::macro_("__SSE4_1__", Some("SSE4.1 enabled")),
CompletionResult::macro_("__SSE4_2__", Some("SSE4.2 enabled")),
CompletionResult::macro_("__AVX__", Some("AVX enabled")),
CompletionResult::macro_("__AVX2__", Some("AVX2 enabled")),
CompletionResult::macro_("__AVX512F__", Some("AVX-512 Foundation enabled")),
CompletionResult::macro_("__AVX512CD__", Some("AVX-512 CD enabled")),
CompletionResult::macro_("__AVX512BW__", Some("AVX-512 BW enabled")),
CompletionResult::macro_("__AVX512DQ__", Some("AVX-512 DQ enabled")),
CompletionResult::macro_("__AVX512VL__", Some("AVX-512 VL enabled")),
CompletionResult::macro_("__FMA__", Some("FMA enabled")),
CompletionResult::macro_("__BMI__", Some("BMI enabled")),
CompletionResult::macro_("__BMI2__", Some("BMI2 enabled")),
CompletionResult::macro_("__LZCNT__", Some("LZCNT enabled")),
CompletionResult::macro_("__POPCNT__", Some("POPCNT enabled")),
CompletionResult::macro_("__RDRND__", Some("RDRAND enabled")),
CompletionResult::macro_("__RDSEED__", Some("RDSEED enabled")),
CompletionResult::macro_("__AES__", Some("AES-NI enabled")),
CompletionResult::macro_("__PCLMUL__", Some("PCLMUL enabled")),
CompletionResult::macro_("__SHA__", Some("SHA enabled")),
CompletionResult::macro_("__ADX__", Some("ADX enabled")),
CompletionResult::macro_("__MMX__", Some("MMX enabled")),
CompletionResult::macro_("__3dNOW__", Some("3DNow! enabled")),
CompletionResult::macro_("__SGX__", Some("Intel SGX enabled")),
]
}
fn build_operator_completions() -> Vec<CompletionResult> {
vec![
CompletionResult::keyword("operator+"),
CompletionResult::keyword("operator-"),
CompletionResult::keyword("operator*"),
CompletionResult::keyword("operator/"),
CompletionResult::keyword("operator%"),
CompletionResult::keyword("operator^"),
CompletionResult::keyword("operator&"),
CompletionResult::keyword("operator|"),
CompletionResult::keyword("operator~"),
CompletionResult::keyword("operator!"),
CompletionResult::keyword("operator="),
CompletionResult::keyword("operator<"),
CompletionResult::keyword("operator>"),
CompletionResult::keyword("operator+="),
CompletionResult::keyword("operator-="),
CompletionResult::keyword("operator*="),
CompletionResult::keyword("operator/="),
CompletionResult::keyword("operator%="),
CompletionResult::keyword("operator^="),
CompletionResult::keyword("operator&="),
CompletionResult::keyword("operator|="),
CompletionResult::keyword("operator<<"),
CompletionResult::keyword("operator>>"),
CompletionResult::keyword("operator<<="),
CompletionResult::keyword("operator>>="),
CompletionResult::keyword("operator=="),
CompletionResult::keyword("operator!="),
CompletionResult::keyword("operator<="),
CompletionResult::keyword("operator>="),
CompletionResult::keyword("operator&&"),
CompletionResult::keyword("operator||"),
CompletionResult::keyword("operator++"),
CompletionResult::keyword("operator--"),
CompletionResult::keyword("operator,"),
CompletionResult::keyword("operator->"),
CompletionResult::keyword("operator->*"),
CompletionResult::keyword("operator()"),
CompletionResult::keyword("operator[]"),
CompletionResult::keyword("operator co_await"),
CompletionResult::keyword("operator\"\" _"),
]
}
fn build_generic_macros() -> Vec<CompletionResult> {
vec![
CompletionResult::macro_("NULL", Some("Null pointer constant")),
CompletionResult::macro_("EXIT_SUCCESS", Some("Successful program termination")),
CompletionResult::macro_("EXIT_FAILURE", Some("Unsuccessful program termination")),
CompletionResult::macro_("RAND_MAX", Some("Maximum value returned by rand()")),
CompletionResult::macro_("INT_MAX", Some("Maximum int value")),
CompletionResult::macro_("INT_MIN", Some("Minimum int value")),
CompletionResult::macro_("LONG_MAX", Some("Maximum long value")),
CompletionResult::macro_("LONG_MIN", Some("Minimum long value")),
CompletionResult::macro_("LLONG_MAX", Some("Maximum long long value")),
CompletionResult::macro_("LLONG_MIN", Some("Minimum long long value")),
CompletionResult::macro_("UINT_MAX", Some("Maximum unsigned int value")),
CompletionResult::macro_("ULONG_MAX", Some("Maximum unsigned long value")),
CompletionResult::macro_("ULLONG_MAX", Some("Maximum unsigned long long value")),
CompletionResult::macro_("SIZE_MAX", Some("Maximum size_t value")),
CompletionResult::macro_("CHAR_BIT", Some("Number of bits in a char")),
CompletionResult::macro_("SCHAR_MIN", Some("Minimum signed char value")),
CompletionResult::macro_("SCHAR_MAX", Some("Maximum signed char value")),
CompletionResult::macro_("UCHAR_MAX", Some("Maximum unsigned char value")),
CompletionResult::macro_("SHRT_MIN", Some("Minimum short value")),
CompletionResult::macro_("SHRT_MAX", Some("Maximum short value")),
CompletionResult::macro_("USHRT_MAX", Some("Maximum unsigned short value")),
CompletionResult::macro_("FLT_MAX", Some("Maximum float value")),
CompletionResult::macro_("FLT_MIN", Some("Minimum normalized positive float")),
CompletionResult::macro_("DBL_MAX", Some("Maximum double value")),
CompletionResult::macro_("DBL_MIN", Some("Minimum normalized positive double")),
CompletionResult::macro_("LDBL_MAX", Some("Maximum long double value")),
CompletionResult::macro_("LDBL_MIN", Some("Minimum normalized positive long double")),
CompletionResult::macro_("M_PI", Some("π constant")),
CompletionResult::macro_("M_E", Some("e constant")),
CompletionResult::macro_("EOF", Some("End-of-file indicator")),
CompletionResult::macro_("BUFSIZ", Some("Buffer size for setbuf")),
CompletionResult::macro_("FILENAME_MAX", Some("Maximum filename length")),
CompletionResult::macro_("FOPEN_MAX", Some("Maximum number of open files")),
CompletionResult::macro_("SEEK_SET", Some("Seek from beginning")),
CompletionResult::macro_("SEEK_CUR", Some("Seek from current position")),
CompletionResult::macro_("SEEK_END", Some("Seek from end")),
CompletionResult::macro_("TMP_MAX", Some("Maximum number of unique tmp filenames")),
CompletionResult::macro_("MB_CUR_MAX", Some("Maximum multibyte character length")),
CompletionResult::macro_("MB_LEN_MAX", Some("Maximum multibyte length in any locale")),
CompletionResult::macro_("ERANGE", Some("Math range error")),
CompletionResult::macro_("EDOM", Some("Math domain error")),
CompletionResult::macro_("EILSEQ", Some("Illegal byte sequence")),
CompletionResult::macro_("errno", Some("Error number variable")),
CompletionResult::macro_("assert", Some("Assert a condition")),
CompletionResult::macro_("offsetof", Some("Offset of a struct member")),
CompletionResult::macro_("va_start", Some("Initialize variadic argument list")),
CompletionResult::macro_("va_end", Some("Clean up variadic argument list")),
CompletionResult::macro_("va_arg", Some("Get next variadic argument")),
CompletionResult::macro_("va_copy", Some("Copy variadic argument list")),
CompletionResult::macro_("true", Some("Boolean true (stdbool.h)")),
CompletionResult::macro_("false", Some("Boolean false (stdbool.h)")),
CompletionResult::macro_("bool", Some("Boolean type (stdbool.h)")),
]
}
pub struct X86IntrinsicCompletion {
intrinsics: HashMap<String, IntrinsicEntry>,
completions: Vec<CompletionResult>,
}
#[derive(Debug, Clone)]
struct IntrinsicEntry {
name: String,
return_type: String,
params: Vec<(String, String)>,
header: String,
isa_extension: String,
brief: String,
}
impl Default for X86IntrinsicCompletion {
fn default() -> Self {
Self::new()
}
}
impl X86IntrinsicCompletion {
pub fn new() -> Self {
let entries = build_intrinsic_entries();
let completions: Vec<CompletionResult> = entries
.iter()
.map(|e| {
let param_names: Vec<(&str, &str)> = e
.params
.iter()
.map(|(t, n)| (t.as_str(), n.as_str()))
.collect();
CompletionResult::intrinsic(&e.name, ¶m_names, &e.return_type, &e.header)
.with_priority(intrinsic_priority(&e.isa_extension))
})
.collect();
let intrinsics: HashMap<String, IntrinsicEntry> =
entries.into_iter().map(|e| (e.name.clone(), e)).collect();
Self {
intrinsics,
completions,
}
}
pub fn query(&self, prefix: &str) -> Vec<CompletionResult> {
let lower = prefix.to_lowercase();
self.completions
.iter()
.filter(|c| {
c.filter_text
.as_ref()
.unwrap_or(&c.display_text)
.to_lowercase()
.starts_with(&lower)
})
.cloned()
.collect()
}
pub fn get_detail(&self, name: &str) -> Option<&IntrinsicEntry> {
self.intrinsics.get(name)
}
pub fn all(&self) -> &[CompletionResult] {
&self.completions
}
pub fn len(&self) -> usize {
self.intrinsics.len()
}
pub fn is_empty(&self) -> bool {
self.intrinsics.is_empty()
}
}
fn intrinsic_priority(isa: &str) -> i32 {
match isa {
"SSE" | "SSE2" => 95,
"SSE3" | "SSSE3" => 93,
"SSE4.1" | "SSE4.2" => 92,
"AVX" => 90,
"AVX2" => 88,
"FMA" => 87,
"AVX-512" => 85,
"BMI" | "BMI2" => 84,
"AES" => 83,
"SHA" => 82,
"MMX" => 80,
"AMX" => 78,
"IA32" => 75,
_ => 70,
}
}
fn mk_entry(
name: &str,
ret: &str,
params: Vec<(&str, &str)>,
header: &str,
isa: &str,
brief: &str,
) -> IntrinsicEntry {
IntrinsicEntry {
name: name.to_string(),
return_type: ret.to_string(),
params: params
.into_iter()
.map(|(t, n)| (t.to_string(), n.to_string()))
.collect(),
header: header.to_string(),
isa_extension: isa.to_string(),
brief: brief.to_string(),
}
}
fn sse_brief(name: &str) -> &'static str {
if name.contains("loadu") || name.contains("_loadu_") {
"Load unaligned packed values from memory."
} else if name.contains("load") || name.contains("_load_") {
"Load aligned packed values from memory."
} else if name.contains("storeu") || name.contains("_storeu_") {
"Store unaligned packed values to memory."
} else if name.contains("store") || name.contains("_store_") {
"Store aligned packed values to memory."
} else if name.contains("stream") {
"Non-temporal store to memory."
} else if name.contains("setzero") {
"Set all elements to zero."
} else if name.contains("set1") || name.contains("_set1_") {
"Broadcast scalar to all elements."
} else if name.contains("add") && !name.contains("madd") && !name.contains("hadd") {
"Add packed values."
} else if name.contains("sub") && !name.contains("hsub") {
"Subtract packed values."
} else if name.contains("mul") && !name.contains("fmadd") && !name.contains("fmsub") {
"Multiply packed values."
} else if name.contains("div") {
"Divide packed values."
} else if name.contains("sqrt") {
"Square root of packed values."
} else if name.contains("rcp") {
"Approximate reciprocal."
} else if name.contains("rsqrt") {
"Approximate reciprocal square root."
} else if name.contains("min") {
"Minimum of packed values."
} else if name.contains("max") {
"Maximum of packed values."
} else if name.contains("cmpeq") {
"Compare packed values for equality."
} else if name.contains("cmp") && name.contains("mask") {
"Compare packed values, write mask."
} else if name.contains("cmp") {
"Compare packed values."
} else if name.contains("andnot") {
"Bitwise AND-NOT of packed values."
} else if name.contains("and_") || name.contains("and_si") {
"Bitwise AND of packed values."
} else if name.contains("or_") || name.contains("or_si") {
"Bitwise OR of packed values."
} else if name.contains("xor_") || name.contains("xor_si") {
"Bitwise XOR of packed values."
} else if name.contains("shuffle") {
"Shuffle packed values."
} else if name.contains("unpack") {
"Unpack and interleave packed values."
} else if name.contains("blendv") {
"Variable blend of packed values."
} else if name.contains("blend") {
"Blend packed values."
} else if name.contains("fmadd") {
"Fused multiply-add."
} else if name.contains("fmsub") {
"Fused multiply-subtract."
} else if name.contains("fnmadd") {
"Fused negated multiply-add."
} else if name.contains("fnmsub") {
"Fused negated multiply-subtract."
} else if name.contains("fmaddsub") {
"Fused multiply-add/subtract alternating."
} else if name.contains("fmsubadd") {
"Fused multiply-subtract/add alternating."
} else if name.contains("hadd") {
"Horizontal add of packed values."
} else if name.contains("hsub") {
"Horizontal subtract of packed values."
} else if name.contains("madd") {
"Multiply-add packed integers."
} else if name.contains("cvt") || name.contains("_cvt") {
"Convert between packed types."
} else if name.contains("floor") {
"Round down packed values."
} else if name.contains("ceil") {
"Round up packed values."
} else if name.contains("round") {
"Round packed values."
} else if name.contains("gather") {
"Gather elements from memory."
} else if name.contains("maskload") {
"Conditional load from memory."
} else if name.contains("maskstore") {
"Conditional store to memory."
} else if name.contains("broadcast") {
"Broadcast scalar to vector."
} else if name.contains("permute") {
"Permute packed values."
} else if name.contains("extract") {
"Extract element from packed vector."
} else if name.contains("insert") {
"Insert element into packed vector."
} else if name.contains("sll") || name.contains("slli") {
"Logical left shift."
} else if name.contains("sra") || name.contains("srai") {
"Arithmetic right shift."
} else if name.contains("srl") || name.contains("srli") {
"Logical right shift."
} else if name.contains("movemask") {
"Create mask from sign bits."
} else if name.contains("crc32") {
"CRC32 checksum computation."
} else if name.contains("aes") {
"AES encryption/decryption round."
} else if name.contains("sha") {
"SHA hash computation."
} else if name.contains("rdrand") {
"Hardware random number generator."
} else if name.contains("rdseed") {
"Hardware random seed generator."
} else if name.contains("rdtsc") {
"Read Time-Stamp Counter."
} else if name.contains("cpuid") {
"CPU identification."
} else if name.contains("fence")
|| name.contains("mfence")
|| name.contains("lfence")
|| name.contains("sfence")
{
"Memory fence/barrier."
} else {
"X86 intrinsic function."
}
}
fn build_intrinsic_entries() -> Vec<IntrinsicEntry> {
let mut e = Vec::new();
e.push(mk_entry(
"_mm_empty",
"void",
vec![],
"mmintrin.h",
"MMX",
"Empty the MMX state.",
));
e.push(mk_entry(
"_m_empty",
"void",
vec![],
"mmintrin.h",
"MMX",
"Empty the MMX state.",
));
e.push(mk_entry(
"_mm_setzero_si64",
"__m64",
vec![],
"mmintrin.h",
"MMX",
"Set 64-bit MMX value to zero.",
));
e.push(mk_entry(
"_mm_set_pi32",
"__m64",
vec![("int", "i1"), ("int", "i0")],
"mmintrin.h",
"MMX",
"Set 64-bit MMX value from two 32-bit ints.",
));
e.push(mk_entry(
"_mm_cvtsi32_si64",
"__m64",
vec![("int", "a")],
"mmintrin.h",
"MMX",
"Convert 32-bit int to 64-bit MMX value.",
));
e.push(mk_entry(
"_mm_cvtsi64_si32",
"int",
vec![("__m64", "a")],
"mmintrin.h",
"MMX",
"Convert 64-bit MMX value to 32-bit int.",
));
e.push(mk_entry(
"_mm_packs_pi16",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Pack 16-bit ints to 8-bit with saturation.",
));
e.push(mk_entry(
"_mm_packs_pi32",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Pack 32-bit ints to 16-bit with saturation.",
));
e.push(mk_entry(
"_mm_packs_pu16",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Pack 16-bit signed to 8-bit unsigned with saturation.",
));
e.push(mk_entry(
"_mm_unpackhi_pi8",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Unpack high 8-bit ints.",
));
e.push(mk_entry(
"_mm_unpacklo_pi8",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Unpack low 8-bit ints.",
));
e.push(mk_entry(
"_mm_add_pi8",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Add packed 8-bit ints.",
));
e.push(mk_entry(
"_mm_add_pi16",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Add packed 16-bit ints.",
));
e.push(mk_entry(
"_mm_add_pi32",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Add packed 32-bit ints.",
));
e.push(mk_entry(
"_mm_sub_pi8",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Subtract packed 8-bit ints.",
));
e.push(mk_entry(
"_mm_sub_pi16",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Subtract packed 16-bit ints.",
));
e.push(mk_entry(
"_mm_sub_pi32",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Subtract packed 32-bit ints.",
));
e.push(mk_entry(
"_mm_madd_pi16",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Multiply-add packed 16-bit ints.",
));
e.push(mk_entry(
"_mm_mulhi_pi16",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Multiply high packed 16-bit ints.",
));
e.push(mk_entry(
"_mm_mullo_pi16",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Multiply low packed 16-bit ints.",
));
let sse = [
("_mm_load_ss", "__m128", vec![("float const*", "p")]),
("_mm_load_ps", "__m128", vec![("float const*", "p")]),
("_mm_load1_ps", "__m128", vec![("float const*", "p")]),
("_mm_load_ps1", "__m128", vec![("float const*", "p")]),
("_mm_loadr_ps", "__m128", vec![("float const*", "p")]),
("_mm_loadu_ps", "__m128", vec![("float const*", "p")]),
(
"_mm_loadh_pi",
"__m128",
vec![("__m128", "a"), ("__m64 const*", "p")],
),
(
"_mm_loadl_pi",
"__m128",
vec![("__m128", "a"), ("__m64 const*", "p")],
),
(
"_mm_store_ss",
"void",
vec![("float*", "p"), ("__m128", "a")],
),
(
"_mm_store_ps",
"void",
vec![("float*", "p"), ("__m128", "a")],
),
(
"_mm_store1_ps",
"void",
vec![("float*", "p"), ("__m128", "a")],
),
(
"_mm_store_ps1",
"void",
vec![("float*", "p"), ("__m128", "a")],
),
(
"_mm_storer_ps",
"void",
vec![("float*", "p"), ("__m128", "a")],
),
(
"_mm_storeu_ps",
"void",
vec![("float*", "p"), ("__m128", "a")],
),
(
"_mm_storeh_pi",
"void",
vec![("__m64*", "p"), ("__m128", "a")],
),
(
"_mm_storel_pi",
"void",
vec![("__m64*", "p"), ("__m128", "a")],
),
(
"_mm_add_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_add_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_sub_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_sub_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_mul_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_mul_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_div_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_div_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
("_mm_sqrt_ss", "__m128", vec![("__m128", "a")]),
("_mm_sqrt_ps", "__m128", vec![("__m128", "a")]),
("_mm_rcp_ss", "__m128", vec![("__m128", "a")]),
("_mm_rcp_ps", "__m128", vec![("__m128", "a")]),
("_mm_rsqrt_ss", "__m128", vec![("__m128", "a")]),
("_mm_rsqrt_ps", "__m128", vec![("__m128", "a")]),
(
"_mm_min_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_min_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_max_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_max_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpeq_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpeq_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmplt_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmplt_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmple_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmple_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpgt_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpgt_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpge_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpge_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpneq_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpneq_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpnlt_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpnlt_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpnle_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpnle_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpord_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpord_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpunord_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_cmpunord_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_and_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_andnot_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_or_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_xor_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
("_mm_cvtss_si32", "int", vec![("__m128", "a")]),
("_mm_cvttss_si32", "int", vec![("__m128", "a")]),
(
"_mm_cvtsi32_ss",
"__m128",
vec![("__m128", "a"), ("int", "b")],
),
("_mm_cvtpi16_ps", "__m128", vec![("__m64", "a")]),
("_mm_cvtps_pi16", "__m64", vec![("__m128", "a")]),
("_mm_set_ss", "__m128", vec![("float", "w")]),
(
"_mm_set_ps",
"__m128",
vec![
("float", "w"),
("float", "z"),
("float", "y"),
("float", "x"),
],
),
("_mm_set1_ps", "__m128", vec![("float", "w")]),
("_mm_set_ps1", "__m128", vec![("float", "w")]),
(
"_mm_setr_ps",
"__m128",
vec![
("float", "w"),
("float", "z"),
("float", "y"),
("float", "x"),
],
),
("_mm_setzero_ps", "__m128", vec![]),
(
"_mm_shuffle_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("unsigned int", "imm8")],
),
(
"_mm_unpackhi_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_unpacklo_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_movehl_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_movelh_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
("_mm_movemask_ps", "int", vec![("__m128", "a")]),
(
"_mm_prefetch",
"void",
vec![("char const*", "p"), ("int", "i")],
),
("_mm_sfence", "void", vec![]),
(
"_mm_extract_pi16",
"int",
vec![("__m64", "a"), ("int", "n")],
),
(
"_mm_insert_pi16",
"__m64",
vec![("__m64", "a"), ("int", "d"), ("int", "n")],
),
(
"_mm_max_pi16",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
),
("_mm_max_pu8", "__m64", vec![("__m64", "a"), ("__m64", "b")]),
(
"_mm_min_pi16",
"__m64",
vec![("__m64", "a"), ("__m64", "b")],
),
("_mm_min_pu8", "__m64", vec![("__m64", "a"), ("__m64", "b")]),
("_mm_movemask_pi8", "int", vec![("__m64", "a")]),
(
"_mm_shuffle_pi16",
"__m64",
vec![("__m64", "a"), ("int", "n")],
),
(
"_mm_stream_pi",
"void",
vec![("__m64*", "p"), ("__m64", "a")],
),
(
"_mm_stream_ps",
"void",
vec![("float*", "p"), ("__m128", "a")],
),
];
for (name, ret, params) in &sse {
e.push(mk_entry(
name,
ret,
params.clone(),
"xmmintrin.h",
"SSE",
sse_brief(name),
));
}
let sse2 = [
(
"_mm_add_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_add_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_sub_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_sub_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_mul_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_mul_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_div_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_div_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_sqrt_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
("_mm_sqrt_pd", "__m128d", vec![("__m128d", "a")]),
(
"_mm_min_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_min_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_max_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_max_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_add_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_add_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_add_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_add_epi64",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_sub_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_sub_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_sub_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_sub_epi64",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_madd_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_mullo_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_sad_epu8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
("_mm_load_sd", "__m128d", vec![("double const*", "p")]),
("_mm_load_pd", "__m128d", vec![("double const*", "p")]),
("_mm_loadu_pd", "__m128d", vec![("double const*", "p")]),
("_mm_load_si128", "__m128i", vec![("__m128i const*", "p")]),
("_mm_loadu_si128", "__m128i", vec![("__m128i const*", "p")]),
(
"_mm_store_sd",
"void",
vec![("double*", "p"), ("__m128d", "a")],
),
(
"_mm_store_pd",
"void",
vec![("double*", "p"), ("__m128d", "a")],
),
(
"_mm_storeu_pd",
"void",
vec![("double*", "p"), ("__m128d", "a")],
),
(
"_mm_store_si128",
"void",
vec![("__m128i*", "p"), ("__m128i", "a")],
),
(
"_mm_storeu_si128",
"void",
vec![("__m128i*", "p"), ("__m128i", "a")],
),
(
"_mm_stream_si128",
"void",
vec![("__m128i*", "p"), ("__m128i", "a")],
),
(
"_mm_stream_pd",
"void",
vec![("double*", "p"), ("__m128d", "a")],
),
("_mm_cvtsd_si32", "int", vec![("__m128d", "a")]),
("_mm_cvttsd_si32", "int", vec![("__m128d", "a")]),
(
"_mm_cvtsi32_sd",
"__m128d",
vec![("__m128d", "a"), ("int", "b")],
),
(
"_mm_cvtss_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128", "b")],
),
(
"_mm_cvtsd_ss",
"__m128",
vec![("__m128", "a"), ("__m128d", "b")],
),
("_mm_cvtps_pd", "__m128d", vec![("__m128", "a")]),
("_mm_cvtpd_ps", "__m128", vec![("__m128d", "a")]),
("_mm_cvtepi32_pd", "__m128d", vec![("__m128i", "a")]),
("_mm_cvtepi32_ps", "__m128", vec![("__m128i", "a")]),
("_mm_cvtps_epi32", "__m128i", vec![("__m128", "a")]),
("_mm_cvttps_epi32", "__m128i", vec![("__m128", "a")]),
(
"_mm_packs_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_packs_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_packus_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_unpackhi_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_unpackhi_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_unpackhi_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_unpackhi_epi64",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_unpacklo_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_unpacklo_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_unpacklo_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_unpacklo_epi64",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_slli_epi16",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_slli_epi32",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_slli_epi64",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_srai_epi16",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_srai_epi32",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_srli_epi16",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_srli_epi32",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_srli_epi64",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_slli_si128",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_srli_si128",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_shuffle_epi32",
"__m128i",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_extract_epi16",
"int",
vec![("__m128i", "a"), ("int", "imm8")],
),
(
"_mm_insert_epi16",
"__m128i",
vec![("__m128i", "a"), ("int", "i"), ("int", "imm8")],
),
("_mm_movemask_epi8", "int", vec![("__m128i", "a")]),
("_mm_movemask_pd", "int", vec![("__m128d", "a")]),
(
"_mm_and_si128",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_andnot_si128",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_or_si128",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_xor_si128",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
("_mm_setzero_si128", "__m128i", vec![]),
(
"_mm_set_epi32",
"__m128i",
vec![("int", "i3"), ("int", "i2"), ("int", "i1"), ("int", "i0")],
),
("_mm_set1_epi32", "__m128i", vec![("int", "i")]),
(
"_mm_setr_epi32",
"__m128i",
vec![("int", "i0"), ("int", "i1"), ("int", "i2"), ("int", "i3")],
),
(
"_mm_cmpeq_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_cmpeq_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_cmpeq_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_cmpgt_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_cmpgt_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_cmpgt_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_cmpeq_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_cmpeq_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_cmplt_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_cmplt_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_cmple_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_cmple_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_cmpgt_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_cmpgt_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_cmpge_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_cmpge_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
("_mm_clflush", "void", vec![("void const*", "p")]),
("_mm_lfence", "void", vec![]),
("_mm_mfence", "void", vec![]),
("_mm_pause", "void", vec![]),
("_mm_set_sd", "__m128d", vec![("double", "w")]),
(
"_mm_set_pd",
"__m128d",
vec![("double", "w"), ("double", "x")],
),
("_mm_set1_pd", "__m128d", vec![("double", "w")]),
(
"_mm_setr_pd",
"__m128d",
vec![("double", "x"), ("double", "w")],
),
("_mm_setzero_pd", "__m128d", vec![]),
(
"_mm_shuffle_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b"), ("int", "imm8")],
),
(
"_mm_unpackhi_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_unpacklo_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
];
for (name, ret, params) in &sse2 {
e.push(mk_entry(
name,
ret,
params.clone(),
"emmintrin.h",
"SSE2",
sse_brief(name),
));
}
let sse3 = [
(
"_mm_addsub_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_addsub_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_hadd_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_hadd_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
(
"_mm_hsub_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b")],
),
(
"_mm_hsub_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b")],
),
("_mm_moveldup_ps", "__m128", vec![("__m128", "a")]),
("_mm_movehdup_ps", "__m128", vec![("__m128", "a")]),
("_mm_movedup_pd", "__m128d", vec![("__m128d", "a")]),
("_mm_lddqu_si128", "__m128i", vec![("__m128i const*", "p")]),
];
for (name, ret, params) in &sse3 {
e.push(mk_entry(
name,
ret,
params.clone(),
"pmmintrin.h",
"SSE3",
sse_brief(name),
));
}
let ssse3 = [
(
"_mm_hadd_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_hadd_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_hsub_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_hsub_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_maddubs_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_mulhrs_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_shuffle_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_sign_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_sign_epi16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_sign_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_alignr_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b"), ("int", "count")],
),
("_mm_abs_epi8", "__m128i", vec![("__m128i", "a")]),
("_mm_abs_epi16", "__m128i", vec![("__m128i", "a")]),
("_mm_abs_epi32", "__m128i", vec![("__m128i", "a")]),
];
for (name, ret, params) in &ssse3 {
e.push(mk_entry(
name,
ret,
params.clone(),
"tmmintrin.h",
"SSSE3",
sse_brief(name),
));
}
let sse41 = [
(
"_mm_blend_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("int const", "imm8")],
),
(
"_mm_blend_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b"), ("int const", "imm8")],
),
(
"_mm_blendv_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("__m128", "mask")],
),
(
"_mm_blendv_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b"), ("__m128d", "mask")],
),
(
"_mm_dp_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("int const", "imm8")],
),
("_mm_floor_ps", "__m128", vec![("__m128", "a")]),
("_mm_floor_pd", "__m128d", vec![("__m128d", "a")]),
("_mm_ceil_ps", "__m128", vec![("__m128", "a")]),
("_mm_ceil_pd", "__m128d", vec![("__m128d", "a")]),
(
"_mm_round_ps",
"__m128",
vec![("__m128", "a"), ("int", "rounding")],
),
(
"_mm_round_pd",
"__m128d",
vec![("__m128d", "a"), ("int", "rounding")],
),
(
"_mm_mul_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_mullo_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_cmpeq_epi64",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_extract_ps",
"int",
vec![("__m128", "a"), ("int const", "imm8")],
),
(
"_mm_extract_epi8",
"int",
vec![("__m128i", "a"), ("int const", "imm8")],
),
(
"_mm_extract_epi32",
"int",
vec![("__m128i", "a"), ("int const", "imm8")],
),
(
"_mm_max_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_max_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_max_epu16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_max_epu32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_min_epi8",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_min_epi32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_min_epu16",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_min_epu32",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_testz_si128",
"int",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_testc_si128",
"int",
vec![("__m128i", "a"), ("__m128i", "b")],
),
(
"_mm_testnzc_si128",
"int",
vec![("__m128i", "a"), ("__m128i", "b")],
),
("_mm_stream_load_si128", "__m128i", vec![("__m128i*", "p")]),
];
for (name, ret, params) in &sse41 {
e.push(mk_entry(
name,
ret,
params.clone(),
"smmintrin.h",
"SSE4.1",
sse_brief(name),
));
}
let sse42 = [
(
"_mm_cmpistrm",
"__m128i",
vec![("__m128i", "a"), ("__m128i", "b"), ("int const", "imm8")],
),
(
"_mm_cmpistri",
"int",
vec![("__m128i", "a"), ("__m128i", "b"), ("int const", "imm8")],
),
(
"_mm_cmpestrm",
"__m128i",
vec![
("__m128i", "a"),
("int", "la"),
("__m128i", "b"),
("int", "lb"),
("int const", "imm8"),
],
),
(
"_mm_crc32_u8",
"unsigned int",
vec![("unsigned int", "crc"), ("unsigned char", "v")],
),
(
"_mm_crc32_u16",
"unsigned int",
vec![("unsigned int", "crc"), ("unsigned short", "v")],
),
(
"_mm_crc32_u32",
"unsigned int",
vec![("unsigned int", "crc"), ("unsigned int", "v")],
),
(
"_mm_crc32_u64",
"unsigned __int64",
vec![("unsigned __int64", "crc"), ("unsigned __int64", "v")],
),
];
for (name, ret, params) in &sse42 {
e.push(mk_entry(
name,
ret,
params.clone(),
"nmmintrin.h",
"SSE4.2",
sse_brief(name),
));
}
let avx = [
(
"_mm256_add_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_add_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b")],
),
(
"_mm256_sub_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_sub_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b")],
),
(
"_mm256_mul_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_mul_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b")],
),
(
"_mm256_div_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_div_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b")],
),
("_mm256_sqrt_ps", "__m256", vec![("__m256", "a")]),
("_mm256_sqrt_pd", "__m256d", vec![("__m256d", "a")]),
("_mm256_rcp_ps", "__m256", vec![("__m256", "a")]),
("_mm256_rsqrt_ps", "__m256", vec![("__m256", "a")]),
(
"_mm256_min_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_min_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b")],
),
(
"_mm256_max_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_max_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b")],
),
(
"_mm256_and_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_andnot_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_or_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_xor_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_hadd_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_hsub_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_cmp_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("int const", "imm8")],
),
(
"_mm256_cmp_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b"), ("int const", "imm8")],
),
(
"_mm256_shuffle_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("int const", "imm8")],
),
(
"_mm256_unpackhi_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_unpacklo_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b")],
),
(
"_mm256_blend_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("int const", "imm8")],
),
(
"_mm256_blendv_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("__m256", "mask")],
),
(
"_mm256_round_ps",
"__m256",
vec![("__m256", "a"), ("int", "rounding")],
),
("_mm256_floor_ps", "__m256", vec![("__m256", "a")]),
("_mm256_ceil_ps", "__m256", vec![("__m256", "a")]),
("_mm256_cvtepi32_ps", "__m256", vec![("__m256i", "a")]),
("_mm256_cvtps_epi32", "__m256i", vec![("__m256", "a")]),
("_mm256_cvttps_epi32", "__m256i", vec![("__m256", "a")]),
("_mm256_cvtpd_ps", "__m128", vec![("__m256d", "a")]),
("_mm256_cvtps_pd", "__m256d", vec![("__m128", "a")]),
("_mm256_load_ps", "__m256", vec![("float const*", "p")]),
("_mm256_load_pd", "__m256d", vec![("double const*", "p")]),
("_mm256_loadu_ps", "__m256", vec![("float const*", "p")]),
("_mm256_loadu_pd", "__m256d", vec![("double const*", "p")]),
(
"_mm256_store_ps",
"void",
vec![("float*", "p"), ("__m256", "a")],
),
(
"_mm256_store_pd",
"void",
vec![("double*", "p"), ("__m256d", "a")],
),
(
"_mm256_storeu_ps",
"void",
vec![("float*", "p"), ("__m256", "a")],
),
(
"_mm256_storeu_pd",
"void",
vec![("double*", "p"), ("__m256d", "a")],
),
("_mm256_setzero_ps", "__m256", vec![]),
("_mm256_setzero_pd", "__m256d", vec![]),
("_mm256_setzero_si256", "__m256i", vec![]),
(
"_mm256_set_ps",
"__m256",
vec![
("float", "e7"),
("float", "e6"),
("float", "e5"),
("float", "e4"),
("float", "e3"),
("float", "e2"),
("float", "e1"),
("float", "e0"),
],
),
(
"_mm256_set_pd",
"__m256d",
vec![
("double", "e3"),
("double", "e2"),
("double", "e1"),
("double", "e0"),
],
),
("_mm256_set1_ps", "__m256", vec![("float", "a")]),
("_mm256_set1_pd", "__m256d", vec![("double", "a")]),
("_mm256_movemask_ps", "int", vec![("__m256", "a")]),
("_mm256_movemask_pd", "int", vec![("__m256d", "a")]),
(
"_mm256_extractf128_ps",
"__m128",
vec![("__m256", "a"), ("int const", "imm8")],
),
(
"_mm256_extractf128_pd",
"__m128d",
vec![("__m256d", "a"), ("int const", "imm8")],
),
(
"_mm256_extractf128_si256",
"__m128i",
vec![("__m256i", "a"), ("int const", "imm8")],
),
(
"_mm256_insertf128_ps",
"__m256",
vec![("__m256", "a"), ("__m128", "b"), ("int const", "imm8")],
),
(
"_mm256_insertf128_pd",
"__m256d",
vec![("__m256d", "a"), ("__m128d", "b"), ("int const", "imm8")],
),
(
"_mm256_insertf128_si256",
"__m256i",
vec![("__m256i", "a"), ("__m128i", "b"), ("int const", "imm8")],
),
(
"_mm256_permute2f128_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("int const", "imm8")],
),
(
"_mm256_permute2f128_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b"), ("int const", "imm8")],
),
(
"_mm256_permute2f128_si256",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b"), ("int const", "imm8")],
),
("_mm256_broadcast_ss", "__m256", vec![("float const*", "p")]),
(
"_mm256_broadcast_sd",
"__m256d",
vec![("double const*", "p")],
),
(
"_mm256_broadcast_ps",
"__m256",
vec![("__m128 const*", "p")],
),
(
"_mm256_lddqu_si256",
"__m256i",
vec![("__m256i const*", "p")],
),
(
"_mm256_stream_si256",
"void",
vec![("__m256i*", "p"), ("__m256i", "a")],
),
(
"_mm256_maskload_ps",
"__m256",
vec![("float const*", "p"), ("__m256i", "mask")],
),
(
"_mm256_maskload_pd",
"__m256d",
vec![("double const*", "p"), ("__m256i", "mask")],
),
(
"_mm256_maskstore_ps",
"void",
vec![("float*", "p"), ("__m256i", "mask"), ("__m256", "a")],
),
(
"_mm256_maskstore_pd",
"void",
vec![("double*", "p"), ("__m256i", "mask"), ("__m256d", "a")],
),
];
for (name, ret, params) in &avx {
e.push(mk_entry(
name,
ret,
params.clone(),
"immintrin.h",
"AVX",
sse_brief(name),
));
}
let avx2 = [
(
"_mm256_add_epi8",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_add_epi16",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_add_epi32",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_add_epi64",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_sub_epi32",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_mullo_epi32",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_madd_epi16",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
("_mm256_abs_epi8", "__m256i", vec![("__m256i", "a")]),
("_mm256_abs_epi16", "__m256i", vec![("__m256i", "a")]),
("_mm256_abs_epi32", "__m256i", vec![("__m256i", "a")]),
(
"_mm256_sign_epi8",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_sign_epi16",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_sign_epi32",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_shuffle_epi8",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_shuffle_epi32",
"__m256i",
vec![("__m256i", "a"), ("int const", "imm8")],
),
(
"_mm256_alignr_epi8",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b"), ("int const", "imm8")],
),
(
"_mm256_blend_epi32",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b"), ("int const", "imm8")],
),
(
"_mm256_blendv_epi8",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b"), ("__m256i", "mask")],
),
(
"_mm256_and_si256",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_andnot_si256",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_or_si256",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_xor_si256",
"__m256i",
vec![("__m256i", "a"), ("__m256i", "b")],
),
(
"_mm256_slli_epi32",
"__m256i",
vec![("__m256i", "a"), ("int", "imm8")],
),
(
"_mm256_srai_epi32",
"__m256i",
vec![("__m256i", "a"), ("int", "imm8")],
),
(
"_mm256_srli_epi32",
"__m256i",
vec![("__m256i", "a"), ("int", "imm8")],
),
(
"_mm256_permute4x64_epi64",
"__m256i",
vec![("__m256i", "a"), ("int const", "imm8")],
),
(
"_mm256_permutevar8x32_ps",
"__m256",
vec![("__m256", "a"), ("__m256i", "idx")],
),
(
"_mm256_extracti128_si256",
"__m128i",
vec![("__m256i", "a"), ("int const", "imm8")],
),
(
"_mm256_inserti128_si256",
"__m256i",
vec![("__m256i", "a"), ("__m128i", "b"), ("int const", "imm8")],
),
("_mm256_cvtepi8_epi16", "__m256i", vec![("__m128i", "a")]),
("_mm256_cvtepi8_epi32", "__m256i", vec![("__m128i", "a")]),
("_mm256_cvtepi16_epi32", "__m256i", vec![("__m128i", "a")]),
("_mm256_movemask_epi8", "int", vec![("__m256i", "a")]),
(
"_mm256_stream_load_si256",
"__m256i",
vec![("__m256i const*", "p")],
),
(
"_mm256_i32gather_ps",
"__m256",
vec![
("float const*", "base"),
("__m256i", "vindex"),
("int const", "scale"),
],
),
(
"_mm256_i32gather_pd",
"__m256d",
vec![
("double const*", "base"),
("__m128i", "vindex"),
("int const", "scale"),
],
),
(
"_mm256_i64gather_pd",
"__m256d",
vec![
("double const*", "base"),
("__m256i", "vindex"),
("int const", "scale"),
],
),
(
"_mm256_i32gather_epi32",
"__m256i",
vec![
("int const*", "base"),
("__m256i", "vindex"),
("int const", "scale"),
],
),
(
"_mm256_i64gather_epi64",
"__m256i",
vec![
("__int64 const*", "base"),
("__m256i", "vindex"),
("int const", "scale"),
],
),
];
for (name, ret, params) in &avx2 {
e.push(mk_entry(
name,
ret,
params.clone(),
"immintrin.h",
"AVX2",
sse_brief(name),
));
}
let fma = [
(
"_mm_fmadd_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("__m128", "c")],
),
(
"_mm_fmadd_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b"), ("__m128d", "c")],
),
(
"_mm_fmadd_ss",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("__m128", "c")],
),
(
"_mm_fmadd_sd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b"), ("__m128d", "c")],
),
(
"_mm_fmsub_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("__m128", "c")],
),
(
"_mm_fmsub_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b"), ("__m128d", "c")],
),
(
"_mm_fnmadd_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("__m128", "c")],
),
(
"_mm_fnmadd_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b"), ("__m128d", "c")],
),
(
"_mm_fnmsub_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("__m128", "c")],
),
(
"_mm_fnmsub_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b"), ("__m128d", "c")],
),
(
"_mm_fmaddsub_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("__m128", "c")],
),
(
"_mm_fmaddsub_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b"), ("__m128d", "c")],
),
(
"_mm_fmsubadd_ps",
"__m128",
vec![("__m128", "a"), ("__m128", "b"), ("__m128", "c")],
),
(
"_mm_fmsubadd_pd",
"__m128d",
vec![("__m128d", "a"), ("__m128d", "b"), ("__m128d", "c")],
),
(
"_mm256_fmadd_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("__m256", "c")],
),
(
"_mm256_fmadd_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b"), ("__m256d", "c")],
),
(
"_mm256_fmsub_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("__m256", "c")],
),
(
"_mm256_fmsub_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b"), ("__m256d", "c")],
),
(
"_mm256_fnmadd_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("__m256", "c")],
),
(
"_mm256_fnmadd_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b"), ("__m256d", "c")],
),
(
"_mm256_fnmsub_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("__m256", "c")],
),
(
"_mm256_fnmsub_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b"), ("__m256d", "c")],
),
(
"_mm256_fmaddsub_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("__m256", "c")],
),
(
"_mm256_fmaddsub_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b"), ("__m256d", "c")],
),
(
"_mm256_fmsubadd_ps",
"__m256",
vec![("__m256", "a"), ("__m256", "b"), ("__m256", "c")],
),
(
"_mm256_fmsubadd_pd",
"__m256d",
vec![("__m256d", "a"), ("__m256d", "b"), ("__m256d", "c")],
),
];
for (name, ret, params) in &fma {
e.push(mk_entry(
name,
ret,
params.clone(),
"immintrin.h",
"FMA",
sse_brief(name),
));
}
let avx512 = [
(
"_mm512_add_ps",
"__m512",
vec![("__m512", "a"), ("__m512", "b")],
),
(
"_mm512_add_pd",
"__m512d",
vec![("__m512d", "a"), ("__m512d", "b")],
),
(
"_mm512_sub_ps",
"__m512",
vec![("__m512", "a"), ("__m512", "b")],
),
(
"_mm512_sub_pd",
"__m512d",
vec![("__m512d", "a"), ("__m512d", "b")],
),
(
"_mm512_mul_ps",
"__m512",
vec![("__m512", "a"), ("__m512", "b")],
),
(
"_mm512_mul_pd",
"__m512d",
vec![("__m512d", "a"), ("__m512d", "b")],
),
(
"_mm512_div_ps",
"__m512",
vec![("__m512", "a"), ("__m512", "b")],
),
(
"_mm512_div_pd",
"__m512d",
vec![("__m512d", "a"), ("__m512d", "b")],
),
("_mm512_sqrt_ps", "__m512", vec![("__m512", "a")]),
("_mm512_sqrt_pd", "__m512d", vec![("__m512d", "a")]),
(
"_mm512_fmadd_ps",
"__m512",
vec![("__m512", "a"), ("__m512", "b"), ("__m512", "c")],
),
(
"_mm512_fmadd_pd",
"__m512d",
vec![("__m512d", "a"), ("__m512d", "b"), ("__m512d", "c")],
),
(
"_mm512_fmsub_ps",
"__m512",
vec![("__m512", "a"), ("__m512", "b"), ("__m512", "c")],
),
(
"_mm512_fmsub_pd",
"__m512d",
vec![("__m512d", "a"), ("__m512d", "b"), ("__m512d", "c")],
),
(
"_mm512_min_ps",
"__m512",
vec![("__m512", "a"), ("__m512", "b")],
),
(
"_mm512_min_pd",
"__m512d",
vec![("__m512d", "a"), ("__m512d", "b")],
),
(
"_mm512_max_ps",
"__m512",
vec![("__m512", "a"), ("__m512", "b")],
),
(
"_mm512_max_pd",
"__m512d",
vec![("__m512d", "a"), ("__m512d", "b")],
),
("_mm512_setzero_ps", "__m512", vec![]),
("_mm512_setzero_pd", "__m512d", vec![]),
("_mm512_setzero_si512", "__m512i", vec![]),
("_mm512_set1_ps", "__m512", vec![("float", "a")]),
("_mm512_set1_pd", "__m512d", vec![("double", "a")]),
("_mm512_load_ps", "__m512", vec![("void const*", "p")]),
("_mm512_load_pd", "__m512d", vec![("void const*", "p")]),
(
"_mm512_store_ps",
"void",
vec![("void*", "p"), ("__m512", "a")],
),
(
"_mm512_store_pd",
"void",
vec![("void*", "p"), ("__m512d", "a")],
),
(
"_mm512_add_epi32",
"__m512i",
vec![("__m512i", "a"), ("__m512i", "b")],
),
(
"_mm512_add_epi64",
"__m512i",
vec![("__m512i", "a"), ("__m512i", "b")],
),
(
"_mm512_sub_epi32",
"__m512i",
vec![("__m512i", "a"), ("__m512i", "b")],
),
(
"_mm512_sub_epi64",
"__m512i",
vec![("__m512i", "a"), ("__m512i", "b")],
),
(
"_mm512_mullo_epi32",
"__m512i",
vec![("__m512i", "a"), ("__m512i", "b")],
),
(
"_mm512_and_si512",
"__m512i",
vec![("__m512i", "a"), ("__m512i", "b")],
),
(
"_mm512_or_si512",
"__m512i",
vec![("__m512i", "a"), ("__m512i", "b")],
),
(
"_mm512_xor_si512",
"__m512i",
vec![("__m512i", "a"), ("__m512i", "b")],
),
(
"_mm512_mask_add_ps",
"__m512",
vec![
("__m512", "src"),
("__mmask16", "k"),
("__m512", "a"),
("__m512", "b"),
],
),
(
"_mm512_mask_add_pd",
"__m512d",
vec![
("__m512d", "src"),
("__mmask8", "k"),
("__m512d", "a"),
("__m512d", "b"),
],
),
(
"_mm512_maskz_add_ps",
"__m512",
vec![("__mmask16", "k"), ("__m512", "a"), ("__m512", "b")],
),
(
"_mm512_maskz_add_pd",
"__m512d",
vec![("__mmask8", "k"), ("__m512d", "a"), ("__m512d", "b")],
),
(
"_mm512_cmp_ps_mask",
"__mmask16",
vec![("__m512", "a"), ("__m512", "b"), ("int const", "imm8")],
),
(
"_mm512_cmp_pd_mask",
"__mmask8",
vec![("__m512d", "a"), ("__m512d", "b"), ("int const", "imm8")],
),
];
for (name, ret, params) in &avx512 {
e.push(mk_entry(
name,
ret,
params.clone(),
"zmmintrin.h",
"AVX-512",
sse_brief(name),
));
}
let ia32 = [
("__builtin_ia32_rdtsc", "unsigned long long", vec![]),
(
"__builtin_ia32_rdtscp",
"unsigned long long",
vec![("unsigned int*", "aux")],
),
(
"__builtin_ia32_rdpmc",
"unsigned long long",
vec![("int", "counter")],
),
("__builtin_ia32_pause", "void", vec![]),
("__builtin_ia32_lfence", "void", vec![]),
("__builtin_ia32_mfence", "void", vec![]),
("__builtin_ia32_sfence", "void", vec![]),
(
"__builtin_ia32_cpuid",
"void",
vec![
("unsigned int*", "info"),
("unsigned int", "eax"),
("unsigned int", "ecx"),
],
),
(
"__builtin_ia32_xgetbv",
"unsigned long long",
vec![("unsigned int", "xcr")],
),
(
"__builtin_ia32_rdrand32_step",
"int",
vec![("unsigned int*", "val")],
),
(
"__builtin_ia32_rdrand64_step",
"int",
vec![("unsigned long long*", "val")],
),
(
"__builtin_ia32_rdseed32_step",
"int",
vec![("unsigned int*", "val")],
),
(
"__builtin_ia32_rdseed64_step",
"int",
vec![("unsigned long long*", "val")],
),
(
"__builtin_ia32_lzcnt_u32",
"unsigned int",
vec![("unsigned int", "x")],
),
(
"__builtin_ia32_lzcnt_u64",
"unsigned long long",
vec![("unsigned long long", "x")],
),
(
"__builtin_ia32_tzcnt_u32",
"unsigned int",
vec![("unsigned int", "x")],
),
(
"__builtin_ia32_tzcnt_u64",
"unsigned long long",
vec![("unsigned long long", "x")],
),
(
"__builtin_ia32_crc32qi",
"unsigned int",
vec![("unsigned int", "crc"), ("unsigned char", "v")],
),
(
"__builtin_ia32_crc32hi",
"unsigned int",
vec![("unsigned int", "crc"), ("unsigned short", "v")],
),
(
"__builtin_ia32_crc32si",
"unsigned int",
vec![("unsigned int", "crc"), ("unsigned int", "v")],
),
(
"__builtin_ia32_crc32di",
"unsigned long long",
vec![("unsigned long long", "crc"), ("unsigned long long", "v")],
),
];
for (name, ret, params) in &ia32 {
e.push(mk_entry(
name,
ret,
params.clone(),
"ia32intrin.h",
"IA32",
sse_brief(name),
));
}
e
}
pub struct X86TypeCompletion {
struct_members: HashMap<String, Vec<CompletionResult>>,
enum_members: HashMap<String, Vec<CompletionResult>>,
class_members: HashMap<String, Vec<CompletionResult>>,
namespace_members: HashMap<String, Vec<CompletionResult>>,
}
impl Default for X86TypeCompletion {
fn default() -> Self {
Self::new()
}
}
impl X86TypeCompletion {
pub fn new() -> Self {
Self {
struct_members: HashMap::new(),
enum_members: HashMap::new(),
class_members: HashMap::new(),
namespace_members: HashMap::new(),
}
}
pub fn register_struct(&mut self, name: &str, members: &[CompletionResult]) {
self.struct_members
.insert(name.to_string(), members.to_vec());
}
pub fn register_enum(&mut self, name: &str, enumerators: &[CompletionResult]) {
self.enum_members
.insert(name.to_string(), enumerators.to_vec());
}
pub fn register_class(&mut self, name: &str, members: &[CompletionResult]) {
self.class_members
.insert(name.to_string(), members.to_vec());
}
pub fn register_namespace(&mut self, name: &str, members: &[CompletionResult]) {
self.namespace_members
.insert(name.to_string(), members.to_vec());
}
pub fn query_members(&self, type_name: &str, prefix: &str) -> Vec<CompletionResult> {
let mut r = Vec::new();
let lower = prefix.to_lowercase();
if let Some(members) = self.struct_members.get(type_name) {
for m in members {
let ft = m.filter_text.as_ref().unwrap_or(&m.display_text);
if ft.to_lowercase().starts_with(&lower) {
r.push(m.clone());
}
}
}
if let Some(members) = self.class_members.get(type_name) {
for m in members {
let ft = m.filter_text.as_ref().unwrap_or(&m.display_text);
if ft.to_lowercase().starts_with(&lower) {
r.push(m.clone());
}
}
}
if prefix.is_empty() {
r.sort_by_key(|k| -k.priority);
}
r
}
pub fn query_scope(&self, scope_name: &str, prefix: &str) -> Vec<CompletionResult> {
let mut r = Vec::new();
if let Some(members) = self.enum_members.get(scope_name) {
r.extend(members.iter().cloned());
}
if let Some(members) = self.namespace_members.get(scope_name) {
r.extend(members.iter().cloned());
}
if let Some(members) = self.class_members.get(scope_name) {
r.extend(members.iter().cloned());
}
let lower = prefix.to_lowercase();
r.retain(|x| {
let ft = x.filter_text.as_ref().unwrap_or(&x.display_text);
ft.to_lowercase().starts_with(&lower)
});
r.sort_by_key(|k| -k.priority);
r
}
pub fn query_enum_values(&self, enum_name: &str, prefix: &str) -> Vec<CompletionResult> {
let lower = prefix.to_lowercase();
if let Some(enumerators) = self.enum_members.get(enum_name) {
enumerators
.iter()
.filter(|e| {
let ft = e.filter_text.as_ref().unwrap_or(&e.display_text);
ft.to_lowercase().starts_with(&lower)
})
.cloned()
.collect()
} else {
Vec::new()
}
}
pub fn all_type_names(&self) -> Vec<CompletionResult> {
let mut r = Vec::new();
for name in self.struct_members.keys() {
r.push(CompletionResult::type_(name, Some("struct")));
}
for name in self.enum_members.keys() {
r.push(CompletionResult::type_(name, Some("enum")));
}
for name in self.class_members.keys() {
r.push(CompletionResult::type_(name, Some("class")));
}
r.sort_by_key(|k| k.display_text.clone());
r
}
}
pub struct X86MacroCompletion {
user_macros: HashMap<String, MacroDef>,
builtin_macros: Vec<CompletionResult>,
}
#[derive(Debug, Clone)]
pub struct MacroDef {
pub name: String,
pub is_function_like: bool,
pub params: Vec<String>,
pub body: String,
}
impl X86MacroCompletion {
pub fn new(builtin_macros: Vec<CompletionResult>) -> Self {
Self {
user_macros: HashMap::new(),
builtin_macros,
}
}
pub fn define(&mut self, name: &str, def: MacroDef) {
self.user_macros.insert(name.to_string(), def);
}
pub fn undefine(&mut self, name: &str) {
self.user_macros.remove(name);
}
pub fn query(&self, prefix: &str) -> Vec<CompletionResult> {
let lower = prefix.to_lowercase();
let mut r: Vec<CompletionResult> = Vec::new();
for (name, def) in &self.user_macros {
if name.to_lowercase().starts_with(&lower) {
let doc = if def.is_function_like {
format!("#define {}({}) {}", name, def.params.join(", "), def.body)
} else {
format!("#define {} {}", name, def.body)
};
r.push(CompletionResult::macro_(name, Some(&doc)).with_priority(92));
}
}
for bm in &self.builtin_macros {
let ft = bm.filter_text.as_ref().unwrap_or(&bm.display_text);
if ft.to_lowercase().starts_with(&lower) {
r.push(bm.clone());
}
}
r.sort_by_key(|k| -k.priority);
r
}
pub fn is_defined(&self, name: &str) -> bool {
self.user_macros.contains_key(name)
}
pub fn get_definition(&self, name: &str) -> Option<&MacroDef> {
self.user_macros.get(name)
}
pub fn macro_count(&self) -> usize {
self.user_macros.len()
}
}
pub struct X86HeaderCompletion {
system_include_paths: Vec<PathBuf>,
user_include_paths: Vec<PathBuf>,
c_standard_headers: Vec<String>,
cxx_standard_headers: Vec<String>,
x86_headers: Vec<String>,
}
impl Default for X86HeaderCompletion {
fn default() -> Self {
Self::new()
}
}
impl X86HeaderCompletion {
pub fn new() -> Self {
let c = vec![
"assert.h",
"complex.h",
"ctype.h",
"errno.h",
"fenv.h",
"float.h",
"inttypes.h",
"iso646.h",
"limits.h",
"locale.h",
"math.h",
"setjmp.h",
"signal.h",
"stdalign.h",
"stdarg.h",
"stdatomic.h",
"stdbool.h",
"stddef.h",
"stdint.h",
"stdio.h",
"stdlib.h",
"stdnoreturn.h",
"string.h",
"tgmath.h",
"threads.h",
"time.h",
"uchar.h",
"wchar.h",
"wctype.h",
];
let cxx = vec![
"algorithm",
"array",
"atomic",
"bitset",
"chrono",
"complex",
"condition_variable",
"deque",
"exception",
"filesystem",
"forward_list",
"fstream",
"functional",
"future",
"initializer_list",
"iomanip",
"ios",
"iosfwd",
"iostream",
"istream",
"iterator",
"limits",
"list",
"locale",
"map",
"memory",
"mutex",
"new",
"numeric",
"optional",
"ostream",
"queue",
"random",
"ratio",
"regex",
"set",
"shared_mutex",
"sstream",
"stack",
"stdexcept",
"streambuf",
"string",
"string_view",
"system_error",
"thread",
"tuple",
"type_traits",
"typeindex",
"typeinfo",
"unordered_map",
"unordered_set",
"utility",
"valarray",
"variant",
"vector",
];
let x86 = vec![
"xmmintrin.h",
"emmintrin.h",
"pmmintrin.h",
"tmmintrin.h",
"smmintrin.h",
"nmmintrin.h",
"immintrin.h",
"zmmintrin.h",
"mmintrin.h",
"x86intrin.h",
"ia32intrin.h",
"bmiintrin.h",
"bmi2intrin.h",
"lzcntintrin.h",
"fmaintrin.h",
"avxintrin.h",
"avx2intrin.h",
"avx512fintrin.h",
"avx512cdintrin.h",
"avx512bwintrin.h",
"avx512dqintrin.h",
"avx512vlbwintrin.h",
"avx512vldqintrin.h",
"avx512ifmaintrin.h",
"avx512vbmiintrin.h",
"avx512vnniintrin.h",
"rtmintrin.h",
"shaintrin.h",
"adxintrin.h",
"sgxintrin.h",
"cetintrin.h",
"gfniintrin.h",
"vaesintrin.h",
"vpclmulqdqintrin.h",
];
let mut sys = Vec::new();
sys.push(PathBuf::from("/usr/include"));
sys.push(PathBuf::from("/usr/local/include"));
Self {
system_include_paths: sys,
user_include_paths: Vec::new(),
c_standard_headers: c.iter().map(|s| s.to_string()).collect(),
cxx_standard_headers: cxx.iter().map(|s| s.to_string()).collect(),
x86_headers: x86.iter().map(|s| s.to_string()).collect(),
}
}
pub fn add_system_path(&mut self, path: &Path) {
if !self.system_include_paths.contains(&path.to_path_buf()) {
self.system_include_paths.push(path.to_path_buf());
}
}
pub fn add_user_path(&mut self, path: &Path) {
if !self.user_include_paths.contains(&path.to_path_buf()) {
self.user_include_paths.push(path.to_path_buf());
}
}
pub fn query_user_include(&self, partial: &str, _cf: Option<&Path>) -> Vec<CompletionResult> {
let mut r = Vec::new();
for h in &self.c_standard_headers {
if h.starts_with(partial) {
r.push(CompletionResult::file(h));
}
}
for h in &self.cxx_standard_headers {
if h.starts_with(partial) {
r.push(CompletionResult::file(h));
}
let hf = format!("{}.h", h);
if hf.starts_with(partial) {
r.push(CompletionResult::file(&hf));
}
}
for h in &self.x86_headers {
if h.starts_with(partial) {
r.push(CompletionResult::file(h));
}
}
r.sort_by(|a, b| a.display_text.cmp(&b.display_text));
r.dedup_by(|a, b| a.display_text == b.display_text);
r
}
pub fn query_system_include(&self, partial: &str) -> Vec<CompletionResult> {
let mut r = Vec::new();
for h in &self.c_standard_headers {
if h.starts_with(partial) {
r.push(CompletionResult::file(h));
}
}
for h in &self.cxx_standard_headers {
if h.starts_with(partial) {
r.push(CompletionResult::file(h));
}
}
for h in &self.x86_headers {
if h.starts_with(partial) {
r.push(CompletionResult::file(h));
}
}
let subdirs = [
"sys/", "bits/", "linux/", "asm/", "c++/", "arpa/", "net/", "netinet/",
];
for d in &subdirs {
if d.starts_with(partial) {
r.push(CompletionResult::file(d));
}
}
r.sort_by(|a, b| a.display_text.cmp(&b.display_text));
r
}
pub fn c_headers(&self) -> &[String] {
&self.c_standard_headers
}
pub fn cxx_headers(&self) -> &[String] {
&self.cxx_standard_headers
}
pub fn x86_headers(&self) -> &[String] {
&self.x86_headers
}
}
pub struct X86CallTipProvider {
signatures: HashMap<String, Vec<FunctionSignature>>,
}
#[derive(Debug, Clone)]
pub struct FunctionSignature {
pub return_type: String,
pub params: Vec<(String, String, Option<String>)>,
pub documentation: Option<String>,
pub deprecated: bool,
}
#[derive(Debug, Clone)]
pub struct CallTip {
pub name: String,
pub signature: String,
pub active_param: usize,
pub overloads: Vec<String>,
pub documentation: Option<String>,
}
impl Default for X86CallTipProvider {
fn default() -> Self {
let mut p = Self::new();
p.register_standard_library();
p
}
}
impl X86CallTipProvider {
pub fn new() -> Self {
Self {
signatures: HashMap::new(),
}
}
pub fn register(
&mut self,
name: &str,
return_type: &str,
params: Vec<(&str, &str, Option<&str>)>,
doc: Option<&str>,
) {
let converted: Vec<(String, String, Option<String>)> = params
.into_iter()
.map(|(t, n, d)| (t.to_string(), n.to_string(), d.map(|s| s.to_string())))
.collect();
let sig = FunctionSignature {
return_type: return_type.to_string(),
params: converted,
documentation: doc.map(|s| s.to_string()),
deprecated: false,
};
self.signatures
.entry(name.to_string())
.or_default()
.push(sig);
}
pub fn get_call_tip(&self, name: &str, _arg_index: usize) -> Option<CallTip> {
let overloads = self.signatures.get(name)?;
if overloads.is_empty() {
return None;
}
let active = overloads.first()?;
let formatted = format_signature(name, active);
let all_sigs: Vec<String> = overloads
.iter()
.map(|s| format_signature(name, s))
.collect();
Some(CallTip {
name: name.to_string(),
signature: formatted,
active_param: 0,
overloads: all_sigs,
documentation: active.documentation.clone(),
})
}
pub fn overload_count(&self, name: &str) -> usize {
self.signatures.get(name).map(|s| s.len()).unwrap_or(0)
}
fn register_standard_library(&mut self) {
self.register(
"printf",
"int",
vec![("const char*", "format", None), ("...", "", None)],
Some("Print formatted output to stdout."),
);
self.register(
"fprintf",
"int",
vec![
("FILE*", "stream", None),
("const char*", "format", None),
("...", "", None),
],
Some("Print formatted output to a stream."),
);
self.register(
"sprintf",
"int",
vec![
("char*", "buffer", None),
("const char*", "format", None),
("...", "", None),
],
Some("Print formatted output to a string."),
);
self.register(
"snprintf",
"int",
vec![
("char*", "buffer", None),
("size_t", "size", None),
("const char*", "format", None),
("...", "", None),
],
Some("Print formatted output to a string with size limit."),
);
self.register(
"fopen",
"FILE*",
vec![
("const char*", "filename", None),
("const char*", "mode", None),
],
Some("Open a file."),
);
self.register(
"malloc",
"void*",
vec![("size_t", "size", None)],
Some("Allocate memory."),
);
self.register(
"calloc",
"void*",
vec![("size_t", "num", None), ("size_t", "size", None)],
Some("Allocate and zero-initialize memory."),
);
self.register(
"realloc",
"void*",
vec![("void*", "ptr", None), ("size_t", "size", None)],
Some("Reallocate memory."),
);
self.register(
"free",
"void",
vec![("void*", "ptr", None)],
Some("Free allocated memory."),
);
self.register(
"atoi",
"int",
vec![("const char*", "str", None)],
Some("Convert string to int."),
);
self.register(
"atof",
"double",
vec![("const char*", "str", None)],
Some("Convert string to double."),
);
self.register(
"memcpy",
"void*",
vec![
("void*", "dest", None),
("const void*", "src", None),
("size_t", "n", None),
],
Some("Copy n bytes from src to dest."),
);
self.register(
"memmove",
"void*",
vec![
("void*", "dest", None),
("const void*", "src", None),
("size_t", "n", None),
],
Some("Copy n bytes (handles overlapping regions)."),
);
self.register(
"memset",
"void*",
vec![
("void*", "ptr", None),
("int", "value", None),
("size_t", "n", None),
],
Some("Set n bytes to value."),
);
self.register(
"strcpy",
"char*",
vec![("char*", "dest", None), ("const char*", "src", None)],
Some("Copy a null-terminated string."),
);
self.register(
"strncpy",
"char*",
vec![
("char*", "dest", None),
("const char*", "src", None),
("size_t", "n", None),
],
Some("Copy at most n characters of a string."),
);
self.register(
"strlen",
"size_t",
vec![("const char*", "str", None)],
Some("Get string length."),
);
self.register(
"strcmp",
"int",
vec![("const char*", "s1", None), ("const char*", "s2", None)],
Some("Compare two strings."),
);
self.register(
"strncmp",
"int",
vec![
("const char*", "s1", None),
("const char*", "s2", None),
("size_t", "n", None),
],
Some("Compare at most n characters of two strings."),
);
self.register(
"strchr",
"char*",
vec![("const char*", "str", None), ("int", "ch", None)],
Some("Find first occurrence of character in string."),
);
self.register(
"strstr",
"char*",
vec![
("const char*", "haystack", None),
("const char*", "needle", None),
],
Some("Find first occurrence of substring."),
);
self.register(
"sin",
"double",
vec![("double", "x", None)],
Some("Sine function."),
);
self.register(
"cos",
"double",
vec![("double", "x", None)],
Some("Cosine function."),
);
self.register(
"tan",
"double",
vec![("double", "x", None)],
Some("Tangent function."),
);
self.register(
"sqrt",
"double",
vec![("double", "x", None)],
Some("Square root."),
);
self.register(
"pow",
"double",
vec![("double", "base", None), ("double", "exp", None)],
Some("Exponentiation."),
);
self.register(
"exp",
"double",
vec![("double", "x", None)],
Some("Exponential function (e^x)."),
);
self.register(
"log",
"double",
vec![("double", "x", None)],
Some("Natural logarithm."),
);
self.register(
"log10",
"double",
vec![("double", "x", None)],
Some("Base-10 logarithm."),
);
self.register(
"fabs",
"double",
vec![("double", "x", None)],
Some("Absolute value."),
);
self.register(
"ceil",
"double",
vec![("double", "x", None)],
Some("Ceiling function."),
);
self.register(
"floor",
"double",
vec![("double", "x", None)],
Some("Floor function."),
);
self.register(
"fmod",
"double",
vec![("double", "x", None), ("double", "y", None)],
Some("Floating-point remainder."),
);
self.register(
"round",
"double",
vec![("double", "x", None)],
Some("Round to nearest integer."),
);
self.register(
"time",
"time_t",
vec![("time_t*", "timer", None)],
Some("Get current time."),
);
self.register(
"signal",
"void (*)(int)",
vec![("int", "sig", None), ("void (*)(int)", "handler", None)],
Some("Set signal handler."),
);
self.register(
"raise",
"int",
vec![("int", "sig", None)],
Some("Send a signal."),
);
}
}
fn format_signature(name: &str, sig: &FunctionSignature) -> String {
let params: Vec<String> = sig
.params
.iter()
.map(|(t, n, d)| {
if let Some(default) = d {
format!("{} {} = {}", t, n, default)
} else if n.is_empty() {
t.clone()
} else {
format!("{} {}", t, n)
}
})
.collect();
format!("{} {}({})", sig.return_type, name, params.join(", "))
}
pub struct X86SnippetGenerator {
snippets: Vec<CompletionResult>,
}
impl Default for X86SnippetGenerator {
fn default() -> Self {
Self::new()
}
}
impl X86SnippetGenerator {
pub fn new() -> Self {
Self {
snippets: build_all_snippets(),
}
}
pub fn query(&self, prefix: &str) -> Vec<CompletionResult> {
let lower = prefix.to_lowercase();
self.snippets
.iter()
.filter(|s| {
s.filter_text
.as_ref()
.unwrap_or(&s.display_text)
.to_lowercase()
.starts_with(&lower)
})
.cloned()
.collect()
}
pub fn all(&self) -> &[CompletionResult] {
&self.snippets
}
}
fn build_all_snippets() -> Vec<CompletionResult> {
vec![
CompletionResult::snippet("for","for (${1:int i = 0}; ${2:i < n}; ${3:++i}) {\n\t${4}\n}","for loop"),
CompletionResult::snippet("for-range","for (${1:auto} ${2:x} : ${3:container}) {\n\t${4}\n}","range-based for (C++11)"),
CompletionResult::snippet("while","while (${1:condition}) {\n\t${2}\n}","while loop"),
CompletionResult::snippet("do-while","do {\n\t${1}\n} while (${2:condition});","do-while loop"),
CompletionResult::snippet("if","if (${1:condition}) {\n\t${2}\n}","if statement"),
CompletionResult::snippet("if-else","if (${1:condition}) {\n\t${2}\n} else {\n\t${3}\n}","if-else"),
CompletionResult::snippet("switch","switch (${1:expr}) {\ncase ${2:value}:\n\t${3}\n\tbreak;\ndefault:\n\t${4}\n\tbreak;\n}","switch"),
CompletionResult::snippet("return","return ${1:value};","return"),
CompletionResult::snippet("func","${1:void} ${2:function_name}(${3}) {\n\t${4}\n}","function definition"),
CompletionResult::snippet("main","int main(int argc, char *argv[]) {\n\t${1}\n\treturn 0;\n}","main function"),
CompletionResult::snippet("struct","struct ${1:Name} {\n\t${2}\n};","struct definition"),
CompletionResult::snippet("enum","enum ${1:Name} {\n\t${2:VALUE_0} = 0,\n\t${3:VALUE_1},\n};","enum"),
CompletionResult::snippet("enum-class","enum class ${1:Name} {\n\t${2:Value0},\n\t${3:Value1},\n};","scoped enum (C++11)"),
CompletionResult::snippet("union","union ${1:Name} {\n\t${2}\n};","union"),
CompletionResult::snippet("class","class ${1:Name} {\npublic:\n\t${2}\nprivate:\n\t${3}\n};","class (C++)"),
CompletionResult::snippet("class-inherit","class ${1:Derived} : public ${2:Base} {\npublic:\n\t${3}\n};","class with inheritance"),
CompletionResult::snippet("namespace","namespace ${1:name} {\n\t${2}\n}","namespace (C++)"),
CompletionResult::snippet("include","#include <${1:header.h}>","system header include"),
CompletionResult::snippet("include-local","#include \"${1:header.h}\"","local header include"),
CompletionResult::snippet("define","#define ${1:NAME} ${2:value}","macro definition"),
CompletionResult::snippet("define-func","#define ${1:NAME}(${2:args}) ${3:body}","function-like macro"),
CompletionResult::snippet("ifdef","#ifdef ${1:NAME}\n${2}\n#endif","conditional: if defined"),
CompletionResult::snippet("ifndef","#ifndef ${1:NAME}\n#define ${1:NAME}\n${2}\n#endif","include guard"),
CompletionResult::snippet("include-guard","#ifndef ${1:HEADER_NAME}_H\n#define ${1:HEADER_NAME}_H\n\n${2}\n\n#endif /* ${1:HEADER_NAME}_H */","full include guard"),
CompletionResult::snippet("pragma-once","#pragma once\n\n${1}","pragma once"),
CompletionResult::snippet("error","#error \"${1:message}\"","compiler error directive"),
CompletionResult::snippet("warning","#warning \"${1:message}\"","compiler warning directive"),
CompletionResult::snippet("if-error","if (${1:err} != 0) {\n\t${2:perror(\"error\");}\n\t${3:return -1;}\n}","error check pattern"),
CompletionResult::snippet("goto-cleanup","if (${1:condition}) {\n\t${2:err = -1;}\n\tgoto cleanup;\n}","goto cleanup"),
CompletionResult::snippet("assert","assert(${1:condition} && \"${2:message}\");","assert"),
CompletionResult::snippet("try-catch","try {\n\t${1}\n} catch (const ${2:std::exception}& e) {\n\t${3}\n}","try-catch (C++)"),
CompletionResult::snippet("template","template <typename ${1:T}>\n${2}","template"),
CompletionResult::snippet("template-class","template <typename ${1:T}>\nclass ${2:Name} {\npublic:\n\t${3}\n};","template class"),
CompletionResult::snippet("iter-begin","for (auto it = ${1:container}.begin(); it != ${1:container}.end(); ++it) {\n\t${2}\n}","iterator loop"),
CompletionResult::snippet("asm-basic","__asm__ volatile (\n\t\"${1:instruction}\"\n\t: ${2:/* outputs */}\n\t: ${3:/* inputs */}\n\t: ${4:/* clobbers */}\n);","inline assembly"),
CompletionResult::snippet("attribute","__attribute__((${1:attr}))","attribute"),
CompletionResult::snippet("attribute-packed","__attribute__((packed))","packed"),
CompletionResult::snippet("attribute-aligned","__attribute__((aligned(${1:16})))","alignment"),
CompletionResult::snippet("attribute-noreturn","__attribute__((noreturn))","noreturn"),
CompletionResult::snippet("builtin-expect","__builtin_expect(${1:cond}, ${2:1})","branch prediction"),
CompletionResult::snippet("builtin-prefetch","__builtin_prefetch(${1:addr}, ${2:0}, ${3:3})","data cache prefetch"),
CompletionResult::snippet("vector-size","__attribute__((vector_size(${1:16})))","vector_size"),
CompletionResult::snippet("mm-load-ps","__m128 ${1:v} = _mm_load_ps(${2:ptr});","SSE load"),
CompletionResult::snippet("mm-store-ps","_mm_store_ps(${1:ptr}, ${2:v});","SSE store"),
CompletionResult::snippet("mm-add-ps","__m128 ${1:result} = _mm_add_ps(${2:a}, ${3:b});","SSE add"),
CompletionResult::snippet("mm256-load-ps","__m256 ${1:v} = _mm256_load_ps(${2:ptr});","AVX load"),
CompletionResult::snippet("mm256-add-ps","__m256 ${1:result} = _mm256_add_ps(${2:a}, ${3:b});","AVX add"),
CompletionResult::snippet("mm512-load-ps","__m512 ${1:v} = _mm512_load_ps(${2:ptr});","AVX-512 load"),
CompletionResult::snippet("alignas-64","alignas(64) ${1:float} ${2:data}[${3:16}];","64-byte aligned array"),
CompletionResult::snippet("cpuid","unsigned int ${1:eax}, ${2:ebx}, ${3:ecx}, ${4:edx};\n__asm__ volatile(\"cpuid\"\n\t: \"=a\"(${1:eax}), \"=b\"(${2:ebx}), \"=c\"(${3:ecx}), \"=d\"(${4:edx})\n\t: \"a\"(${5:leaf}), \"c\"(${6:subleaf}));","CPUID wrapper"),
]
}
pub struct X86CodeCompletion {
pub database: X86CompletionDatabase,
pub intrinsics: X86IntrinsicCompletion,
pub type_completion: X86TypeCompletion,
pub macro_completion: X86MacroCompletion,
pub header_completion: X86HeaderCompletion,
pub call_tips: X86CallTipProvider,
pub snippets: X86SnippetGenerator,
pub cxx_mode: bool,
pub max_results: usize,
}
impl Default for X86CodeCompletion {
fn default() -> Self {
Self::new(false)
}
}
impl X86CodeCompletion {
pub fn new(cxx_mode: bool) -> Self {
let database = X86CompletionDatabase::new();
let builtin_macros = database.builtin_macros.clone();
Self {
database,
intrinsics: X86IntrinsicCompletion::new(),
type_completion: X86TypeCompletion::new(),
macro_completion: X86MacroCompletion::new(builtin_macros),
header_completion: X86HeaderCompletion::new(),
call_tips: X86CallTipProvider::default(),
snippets: X86SnippetGenerator::new(),
cxx_mode,
max_results: 100,
}
}
pub fn detect_context(&self, line: &str, column: usize) -> CompletionContext {
CompletionContext::from_source_line(line, column)
}
pub fn complete(&self, context: &CompletionContext, prefix: &str) -> Vec<CompletionResult> {
let mut results = Vec::new();
match context {
CompletionContext::DotAccess { receiver_type } => {
if let Some(type_name) = receiver_type {
results.extend(self.type_completion.query_members(type_name, prefix));
}
}
CompletionContext::ArrowAccess { receiver_type } => {
if let Some(type_name) = receiver_type {
results.extend(self.type_completion.query_members(type_name, prefix));
}
}
CompletionContext::ScopeResolution { scope_name } => {
if let Some(name) = scope_name {
results.extend(self.type_completion.query_scope(name, prefix));
}
results.extend(self.type_completion.all_type_names());
}
CompletionContext::OpenParen { .. } => {
results.extend(self.database.query_keywords(prefix, self.cxx_mode));
}
CompletionContext::TypeName => {
results.extend(self.database.query_keywords(prefix, self.cxx_mode));
results.extend(self.type_completion.all_type_names());
}
CompletionContext::Declaration => {
results.extend(self.database.query_keywords(prefix, self.cxx_mode));
results.extend(self.type_completion.all_type_names());
results.extend(self.snippets.query(prefix));
}
CompletionContext::Directive => {
results.extend(self.database.query_directives(prefix));
}
CompletionContext::IncludeQuote { partial } => {
results.extend(self.header_completion.query_user_include(partial, None));
}
CompletionContext::IncludeAngle { partial } => {
results.extend(self.header_completion.query_system_include(partial));
}
CompletionContext::General => {
results.extend(self.database.query_keywords(prefix, self.cxx_mode));
results.extend(self.intrinsics.query(prefix));
results.extend(self.macro_completion.query(prefix));
results.extend(self.snippets.query(prefix));
results.extend(self.type_completion.all_type_names());
}
CompletionContext::Statement => {
results.extend(self.database.query_keywords(prefix, self.cxx_mode));
results.extend(self.snippets.query(prefix));
results.extend(self.macro_completion.query(prefix));
}
CompletionContext::Return => {
results.extend(self.database.query_keywords(prefix, self.cxx_mode));
results.extend(self.macro_completion.query(prefix));
}
CompletionContext::Case => {
results.extend(self.macro_completion.query(prefix));
}
CompletionContext::Goto => {
results.extend(self.database.query_keywords(prefix, self.cxx_mode));
}
}
let lower = prefix.to_lowercase();
results.retain(|r| {
let ft = r.filter_text.as_ref().unwrap_or(&r.display_text);
ft.to_lowercase().starts_with(&lower)
});
let mut seen = HashSet::new();
results.retain(|r| seen.insert(r.display_text.clone()));
results.sort_by(|a, b| {
b.priority
.cmp(&a.priority)
.then_with(|| a.display_text.cmp(&b.display_text))
});
results.truncate(self.max_results);
results
}
pub fn get_call_tips(&self, function_name: &str, arg_index: usize) -> Option<CallTip> {
self.call_tips.get_call_tip(function_name, arg_index)
}
pub fn define_macro(&mut self, name: &str, def: MacroDef) {
self.macro_completion.define(name, def);
}
pub fn undefine_macro(&mut self, name: &str) {
self.macro_completion.undefine(name);
}
pub fn register_struct(&mut self, name: &str, members: &[CompletionResult]) {
self.type_completion.register_struct(name, members);
}
pub fn register_enum(&mut self, name: &str, enumerators: &[CompletionResult]) {
self.type_completion.register_enum(name, enumerators);
}
pub fn register_class(&mut self, name: &str, members: &[CompletionResult]) {
self.type_completion.register_class(name, members);
}
pub fn register_namespace(&mut self, name: &str, members: &[CompletionResult]) {
self.type_completion.register_namespace(name, members);
}
pub fn add_system_include_path(&mut self, path: &Path) {
self.header_completion.add_system_path(path);
}
pub fn add_user_include_path(&mut self, path: &Path) {
self.header_completion.add_user_path(path);
}
pub fn set_max_results(&mut self, max: usize) {
self.max_results = max;
}
pub fn set_cxx_mode(&mut self, cxx: bool) {
self.cxx_mode = cxx;
}
pub fn intrinsic_count(&self) -> usize {
self.intrinsics.len()
}
pub fn macro_count(&self) -> usize {
self.macro_completion.macro_count()
}
pub fn complete_fuzzy(
&self,
context: &CompletionContext,
prefix: &str,
max_distance: usize,
) -> Vec<CompletionResult> {
let mut results = self.complete(context, prefix);
for r in &mut results {
let distance =
levenshtein_distance(&r.display_text.to_lowercase(), &prefix.to_lowercase());
if distance <= max_distance && distance > 0 {
r.priority -= (distance * 5) as i32;
}
}
results.sort_by(|a, b| {
b.priority
.cmp(&a.priority)
.then_with(|| a.display_text.cmp(&b.display_text))
});
results
}
pub fn score_completion(result: &CompletionResult, prefix: &str) -> i32 {
let mut score = result.priority;
let name = result.filter_text.as_ref().unwrap_or(&result.display_text);
if name.eq_ignore_ascii_case(prefix) {
score += 50;
} else if name.to_lowercase().starts_with(&prefix.to_lowercase()) {
score += 20;
} else if name.to_lowercase().contains(&prefix.to_lowercase()) {
score += 5;
}
if result.deprecated {
score -= 100;
}
score
}
pub fn complete_ranked(
&self,
context: &CompletionContext,
prefix: &str,
) -> Vec<(CompletionResult, i32)> {
self.complete(context, prefix)
.into_iter()
.map(|r| {
let s = Self::score_completion(&r, prefix);
(r, s)
})
.collect()
}
pub fn complete_lsp(
&self,
context: &CompletionContext,
prefix: &str,
) -> Vec<LspCompletionItem> {
self.complete(context, prefix)
.into_iter()
.map(|r| LspCompletionItem {
label: r.display_text.clone(),
kind: Some(r.kind.lsp_kind()),
detail: r.detail.clone(),
documentation: r.documentation.clone(),
insert_text: Some(r.insert_text.clone()),
insert_text_format: if r.is_snippet { 2 } else { 1 },
sort_text: r.sort_text.clone(),
filter_text: r.filter_text.clone(),
deprecated: r.deprecated,
additional_text_edits: r
.additional_edits
.iter()
.map(|e| LspTextEdit {
range: LspRange {
start: LspPosition {
line: e.line as u32,
character: e.column as u32,
},
end: LspPosition {
line: e.line as u32,
character: e.column as u32,
},
},
new_text: e.new_text.clone(),
})
.collect(),
})
.collect()
}
}
#[derive(Debug, Clone)]
pub struct LspCompletionItem {
pub label: String,
pub kind: Option<u32>,
pub detail: Option<String>,
pub documentation: Option<String>,
pub insert_text: Option<String>,
pub insert_text_format: u32,
pub sort_text: Option<String>,
pub filter_text: Option<String>,
pub deprecated: bool,
pub additional_text_edits: Vec<LspTextEdit>,
}
#[derive(Debug, Clone)]
pub struct LspTextEdit {
pub range: LspRange,
pub new_text: String,
}
#[derive(Debug, Clone)]
pub struct LspRange {
pub start: LspPosition,
pub end: LspPosition,
}
#[derive(Debug, Clone)]
pub struct LspPosition {
pub line: u32,
pub character: u32,
}
pub fn levenshtein_distance(a: &str, b: &str) -> usize {
let ac: Vec<char> = a.chars().collect();
let bc: Vec<char> = b.chars().collect();
let al = ac.len();
let bl = bc.len();
if al == 0 {
return bl;
}
if bl == 0 {
return al;
}
let mut prev: Vec<usize> = (0..=bl).collect();
let mut curr = vec![0usize; bl + 1];
for i in 1..=al {
curr[0] = i;
for j in 1..=bl {
let cost = if ac[i - 1] == bc[j - 1] { 0 } else { 1 };
curr[j] = (prev[j] + 1).min(curr[j - 1] + 1).min(prev[j - 1] + cost);
}
std::mem::swap(&mut prev, &mut curr);
}
prev[bl]
}
pub fn fuzzy_match_score(candidate: &str, query: &str) -> u32 {
let cl = candidate.to_lowercase();
let ql = query.to_lowercase();
if cl == ql {
return 100;
}
if cl.starts_with(&ql) {
return 90;
}
if cl.contains(&ql) {
return 70;
}
let mut qi = 0usize;
let mut matches = 0u32;
let mut consec = 0u32;
let mut best = 0u32;
for cc in cl.chars() {
if qi < ql.len() && cc == ql.chars().nth(qi).unwrap() {
matches += 1;
consec += 1;
qi += 1;
if consec > best {
best = consec;
}
} else {
consec = 0;
}
}
if matches == 0 {
return 0;
}
let mr = matches as f64 / ql.len() as f64;
let cb = if best > 1 { 15.0 } else { 0.0 };
let pb = if cl.starts_with(&ql.chars().next().unwrap_or(' ').to_string()) {
10.0
} else {
0.0
};
((mr * 60.0) + cb + pb).min(99.0) as u32
}
pub struct CompletionCache {
cache: HashMap<(String, String), Vec<CompletionResult>>,
max_entries: usize,
hits: u64,
misses: u64,
}
impl CompletionCache {
pub fn new(max_entries: usize) -> Self {
Self {
cache: HashMap::new(),
max_entries,
hits: 0,
misses: 0,
}
}
fn key(context: &CompletionContext, prefix: &str) -> (String, String) {
let tag = match context {
CompletionContext::DotAccess { .. } => "dot",
CompletionContext::ArrowAccess { .. } => "arrow",
CompletionContext::ScopeResolution { .. } => "scope",
CompletionContext::OpenParen { .. } => "paren",
CompletionContext::TypeName => "type",
CompletionContext::Declaration => "decl",
CompletionContext::Directive => "directive",
CompletionContext::IncludeQuote { .. } => "incl_q",
CompletionContext::IncludeAngle { .. } => "incl_a",
CompletionContext::General => "general",
CompletionContext::Statement => "stmt",
CompletionContext::Return => "return",
CompletionContext::Case => "case",
CompletionContext::Goto => "goto",
};
(tag.to_string(), prefix.to_lowercase())
}
pub fn get(
&mut self,
context: &CompletionContext,
prefix: &str,
) -> Option<Vec<CompletionResult>> {
let key = Self::key(context, prefix);
if let Some(results) = self.cache.get(&key) {
self.hits += 1;
Some(results.clone())
} else {
self.misses += 1;
None
}
}
pub fn put(
&mut self,
context: &CompletionContext,
prefix: &str,
results: Vec<CompletionResult>,
) {
if self.cache.len() >= self.max_entries {
if let Some(old_key) = self.cache.keys().next().cloned() {
self.cache.remove(&old_key);
}
}
self.cache.insert(Self::key(context, prefix), results);
}
pub fn hit_rate(&self) -> f64 {
let total = self.hits + self.misses;
if total == 0 {
0.0
} else {
(self.hits as f64 / total as f64) * 100.0
}
}
pub fn clear(&mut self) {
self.cache.clear();
self.hits = 0;
self.misses = 0;
}
pub fn len(&self) -> usize {
self.cache.len()
}
pub fn is_empty(&self) -> bool {
self.cache.is_empty()
}
}
impl Default for CompletionCache {
fn default() -> Self {
Self::new(500)
}
}
pub struct X86ABIIntrinsicCompletion {
entries: Vec<CompletionResult>,
}
impl Default for X86ABIIntrinsicCompletion {
fn default() -> Self {
Self::new()
}
}
impl X86ABIIntrinsicCompletion {
pub fn new() -> Self {
let entries = vec![
CompletionResult::intrinsic(
"__builtin_return_address",
&[("unsigned int", "level")],
"void*",
"<builtin>",
),
CompletionResult::intrinsic(
"__builtin_frame_address",
&[("unsigned int", "level")],
"void*",
"<builtin>",
),
CompletionResult::intrinsic("__builtin_dwarf_cfa", &[], "void*", "<builtin>"),
CompletionResult::intrinsic(
"__builtin_eh_return",
&[("long", "offset"), ("void*", "handler")],
"void",
"<builtin>",
),
CompletionResult::intrinsic(
"__builtin_longjmp",
&[("void*", "buf"), ("int", "val")],
"void",
"<setjmp.h>",
),
CompletionResult::intrinsic(
"__builtin_setjmp",
&[("void*", "buf")],
"int",
"<setjmp.h>",
),
CompletionResult::intrinsic(
"__builtin_stack_restore",
&[("void*", "ptr")],
"void",
"<builtin>",
),
CompletionResult::intrinsic("__builtin_stack_save", &[], "void*", "<builtin>"),
CompletionResult::intrinsic(
"__builtin_alloca_with_align",
&[("size_t", "size"), ("size_t", "alignment")],
"void*",
"<builtin>",
),
CompletionResult::intrinsic(
"__builtin_assume_aligned",
&[
("const void*", "ptr"),
("size_t", "alignment"),
("size_t", "offset"),
],
"void*",
"<builtin>",
),
CompletionResult::intrinsic(
"__builtin___clear_cache",
&[("char*", "begin"), ("char*", "end")],
"void",
"<builtin>",
),
CompletionResult::intrinsic(
"__builtin_object_size",
&[("const void*", "ptr"), ("int", "type")],
"size_t",
"<builtin>",
),
CompletionResult::intrinsic("__builtin_launder", &[("T*", "ptr")], "T*", "<new>"),
CompletionResult::intrinsic("__builtin_addressof", &[("T&", "arg")], "T*", "<builtin>"),
];
Self { entries }
}
pub fn query(&self, prefix: &str) -> Vec<CompletionResult> {
let lower = prefix.to_lowercase();
self.entries
.iter()
.filter(|e| {
e.filter_text
.as_ref()
.unwrap_or(&e.display_text)
.to_lowercase()
.starts_with(&lower)
})
.cloned()
.collect()
}
pub fn all(&self) -> &[CompletionResult] {
&self.entries
}
}
pub struct X86AtomicCompletion {
entries: Vec<CompletionResult>,
}
impl Default for X86AtomicCompletion {
fn default() -> Self {
Self::new()
}
}
impl X86AtomicCompletion {
pub fn new() -> Self {
let entries = vec![
CompletionResult::intrinsic(
"__atomic_load",
&[("const T*", "ptr"), ("int", "memorder")],
"T",
"<builtin>",
),
CompletionResult::intrinsic(
"__atomic_store",
&[("T*", "ptr"), ("T", "val"), ("int", "memorder")],
"void",
"<builtin>",
),
CompletionResult::intrinsic(
"__atomic_exchange",
&[("T*", "ptr"), ("T", "val"), ("int", "memorder")],
"T",
"<builtin>",
),
CompletionResult::intrinsic(
"__atomic_compare_exchange",
&[
("T*", "ptr"),
("T*", "expected"),
("T", "desired"),
("bool", "weak"),
("int", "success"),
("int", "failure"),
],
"bool",
"<builtin>",
),
CompletionResult::intrinsic(
"__atomic_fetch_add",
&[("T*", "ptr"), ("T", "val"), ("int", "memorder")],
"T",
"<builtin>",
),
CompletionResult::intrinsic(
"__atomic_fetch_sub",
&[("T*", "ptr"), ("T", "val"), ("int", "memorder")],
"T",
"<builtin>",
),
CompletionResult::intrinsic(
"__atomic_fetch_and",
&[("T*", "ptr"), ("T", "val"), ("int", "memorder")],
"T",
"<builtin>",
),
CompletionResult::intrinsic(
"__atomic_fetch_xor",
&[("T*", "ptr"), ("T", "val"), ("int", "memorder")],
"T",
"<builtin>",
),
CompletionResult::intrinsic(
"__atomic_fetch_or",
&[("T*", "ptr"), ("T", "val"), ("int", "memorder")],
"T",
"<builtin>",
),
CompletionResult::intrinsic(
"__atomic_thread_fence",
&[("int", "memorder")],
"void",
"<builtin>",
),
CompletionResult::intrinsic(
"__atomic_signal_fence",
&[("int", "memorder")],
"void",
"<builtin>",
),
CompletionResult::intrinsic(
"__sync_fetch_and_add",
&[("T*", "ptr"), ("T", "value")],
"T",
"<builtin>",
),
CompletionResult::intrinsic(
"__sync_fetch_and_sub",
&[("T*", "ptr"), ("T", "value")],
"T",
"<builtin>",
),
CompletionResult::intrinsic(
"__sync_bool_compare_and_swap",
&[("T*", "ptr"), ("T", "oldval"), ("T", "newval")],
"bool",
"<builtin>",
),
CompletionResult::intrinsic(
"__sync_val_compare_and_swap",
&[("T*", "ptr"), ("T", "oldval"), ("T", "newval")],
"T",
"<builtin>",
),
CompletionResult::intrinsic(
"__sync_lock_test_and_set",
&[("T*", "ptr"), ("T", "value")],
"T",
"<builtin>",
),
CompletionResult::intrinsic("__sync_synchronize", &[], "void", "<builtin>"),
];
Self { entries }
}
pub fn query(&self, prefix: &str) -> Vec<CompletionResult> {
let lower = prefix.to_lowercase();
self.entries
.iter()
.filter(|e| {
e.filter_text
.as_ref()
.unwrap_or(&e.display_text)
.to_lowercase()
.starts_with(&lower)
})
.cloned()
.collect()
}
pub fn all(&self) -> &[CompletionResult] {
&self.entries
}
}
pub struct X86SIMDTypeCompletion {
types: Vec<CompletionResult>,
}
impl Default for X86SIMDTypeCompletion {
fn default() -> Self {
Self::new()
}
}
impl X86SIMDTypeCompletion {
pub fn new() -> Self {
let types = vec![
CompletionResult::type_("__m64", Some("64-bit MMX vector")),
CompletionResult::type_("__m128", Some("128-bit SSE float vector")),
CompletionResult::type_("__m128d", Some("128-bit SSE double vector")),
CompletionResult::type_("__m128i", Some("128-bit SSE integer vector")),
CompletionResult::type_("__m256", Some("256-bit AVX float vector")),
CompletionResult::type_("__m256d", Some("256-bit AVX double vector")),
CompletionResult::type_("__m256i", Some("256-bit AVX integer vector")),
CompletionResult::type_("__m512", Some("512-bit AVX-512 float vector")),
CompletionResult::type_("__m512d", Some("512-bit AVX-512 double vector")),
CompletionResult::type_("__m512i", Some("512-bit AVX-512 integer vector")),
CompletionResult::type_("__mmask8", Some("8-bit AVX-512 mask")),
CompletionResult::type_("__mmask16", Some("16-bit AVX-512 mask")),
CompletionResult::type_("__mmask32", Some("32-bit AVX-512 mask")),
CompletionResult::type_("__mmask64", Some("64-bit AVX-512 mask")),
CompletionResult::type_("__m128h", Some("128-bit FP16 vector")),
CompletionResult::type_("__m256h", Some("256-bit FP16 vector")),
CompletionResult::type_("__m512h", Some("512-bit FP16 vector")),
];
Self { types }
}
pub fn query(&self, prefix: &str) -> Vec<CompletionResult> {
let lower = prefix.to_lowercase();
self.types
.iter()
.filter(|t| t.display_text.to_lowercase().starts_with(&lower))
.cloned()
.collect()
}
pub fn all(&self) -> &[CompletionResult] {
&self.types
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_context_dot_access() {
let ctx = CompletionContext::from_source_line("obj.", 3);
assert!(matches!(ctx, CompletionContext::DotAccess { .. }));
if let CompletionContext::DotAccess { receiver_type } = ctx {
assert_eq!(receiver_type, Some("obj".to_string()));
}
}
#[test]
fn test_context_arrow_access() {
let ctx = CompletionContext::from_source_line("ptr->", 5);
assert!(matches!(ctx, CompletionContext::ArrowAccess { .. }));
if let CompletionContext::ArrowAccess { receiver_type } = ctx {
assert_eq!(receiver_type, Some("ptr".to_string()));
}
}
#[test]
fn test_context_scope_resolution() {
let ctx = CompletionContext::from_source_line("std::", 5);
assert!(matches!(ctx, CompletionContext::ScopeResolution { .. }));
if let CompletionContext::ScopeResolution { scope_name } = ctx {
assert_eq!(scope_name, Some("std".to_string()));
}
}
#[test]
fn test_context_open_paren() {
let ctx = CompletionContext::from_source_line("printf(", 7);
assert!(matches!(ctx, CompletionContext::OpenParen { .. }));
if let CompletionContext::OpenParen { callee } = ctx {
assert_eq!(callee, Some("printf".to_string()));
}
}
#[test]
fn test_context_directive() {
let ctx = CompletionContext::from_source_line("#", 1);
assert_eq!(ctx, CompletionContext::Directive);
}
#[test]
fn test_context_include_quote() {
let ctx = CompletionContext::from_source_line("#include \"std", 14);
assert!(matches!(ctx, CompletionContext::IncludeQuote { .. }));
if let CompletionContext::IncludeQuote { partial } = ctx {
assert_eq!(partial, "std");
}
}
#[test]
fn test_context_include_angle() {
let ctx = CompletionContext::from_source_line("#include <std", 14);
assert!(matches!(ctx, CompletionContext::IncludeAngle { .. }));
if let CompletionContext::IncludeAngle { partial } = ctx {
assert_eq!(partial, "std");
}
}
#[test]
fn test_context_return() {
let ctx = CompletionContext::from_source_line("return ", 7);
assert_eq!(ctx, CompletionContext::Return);
}
#[test]
fn test_context_case() {
let ctx = CompletionContext::from_source_line("case ", 5);
assert_eq!(ctx, CompletionContext::Case);
}
#[test]
fn test_context_goto() {
let ctx = CompletionContext::from_source_line("goto ", 5);
assert_eq!(ctx, CompletionContext::Goto);
}
#[test]
fn test_context_type_name() {
let ctx = CompletionContext::from_source_line("struct ", 7);
assert_eq!(ctx, CompletionContext::TypeName);
}
#[test]
fn test_context_general() {
let ctx = CompletionContext::from_source_line("", 0);
assert_eq!(ctx, CompletionContext::General);
}
#[test]
fn test_context_declaration_after_semicolon() {
let ctx = CompletionContext::from_source_line("int x = 5; ", 11);
assert_eq!(ctx, CompletionContext::Declaration);
}
#[test]
fn test_completion_result_keyword() {
let r = CompletionResult::keyword("if");
assert_eq!(r.display_text, "if");
assert_eq!(r.kind, CompletionKind::Keyword);
assert_eq!(r.priority, 100);
assert!(!r.is_snippet);
}
#[test]
fn test_completion_result_macro() {
let r = CompletionResult::macro_("NULL", Some("Null pointer"));
assert_eq!(r.display_text, "NULL");
assert_eq!(r.kind, CompletionKind::Macro);
assert_eq!(r.documentation, Some("Null pointer".to_string()));
}
#[test]
fn test_completion_result_directive() {
let r = CompletionResult::directive("#include", "Include header");
assert_eq!(r.display_text, "#include");
assert_eq!(r.kind, CompletionKind::Directive);
assert_eq!(r.insert_text, "#include ");
}
#[test]
fn test_completion_result_snippet() {
let r = CompletionResult::snippet("for", "for (;;) {}", "for loop");
assert_eq!(r.display_text, "for");
assert_eq!(r.kind, CompletionKind::Snippet);
assert!(r.is_snippet);
}
#[test]
fn test_completion_result_intrinsic() {
let r = CompletionResult::intrinsic(
"_mm_add_ps",
&[("__m128", "a"), ("__m128", "b")],
"__m128",
"xmmintrin.h",
);
assert_eq!(r.display_text, "__m128 _mm_add_ps");
assert_eq!(r.kind, CompletionKind::Intrinsic);
assert!(r.documentation.is_some());
}
#[test]
fn test_completion_result_with_priority() {
let r = CompletionResult::keyword("for").with_priority(200);
assert_eq!(r.priority, 200);
}
#[test]
fn test_completion_result_deprecated() {
let r = CompletionResult::keyword("register").deprecated();
assert!(r.deprecated);
}
#[test]
fn test_completion_kind_icon() {
assert_eq!(CompletionKind::Function.icon(), "f");
assert_eq!(CompletionKind::Variable.icon(), "v");
assert_eq!(CompletionKind::Type.icon(), "t");
assert_eq!(CompletionKind::Macro.icon(), "m");
assert_eq!(CompletionKind::Keyword.icon(), "k");
assert_eq!(CompletionKind::Directive.icon(), "#");
assert_eq!(CompletionKind::Field.icon(), ".");
assert_eq!(CompletionKind::EnumMember.icon(), "e");
assert_eq!(CompletionKind::Snippet.icon(), "~");
}
#[test]
fn test_completion_kind_lsp_kind() {
assert_eq!(CompletionKind::Function.lsp_kind(), 3);
assert_eq!(CompletionKind::Variable.lsp_kind(), 6);
assert_eq!(CompletionKind::Type.lsp_kind(), 7);
}
#[test]
fn test_completion_kind_display() {
assert_eq!(format!("{}", CompletionKind::Function), "function");
assert_eq!(format!("{}", CompletionKind::Keyword), "keyword");
}
#[test]
fn test_database_c_keywords_count() {
let db = X86CompletionDatabase::new();
assert!(db.c_keywords.len() >= 30);
}
#[test]
fn test_database_cxx_keywords_count() {
let db = X86CompletionDatabase::new();
assert!(db.cxx_keywords.len() >= 40);
}
#[test]
fn test_database_x86_keywords_count() {
let db = X86CompletionDatabase::new();
assert!(db.x86_keywords.len() >= 30);
}
#[test]
fn test_database_directives_count() {
let db = X86CompletionDatabase::new();
assert!(db.directives.len() >= 15);
}
#[test]
fn test_query_keywords_c_mode() {
let db = X86CompletionDatabase::new();
let results = db.query_keywords("for", false);
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text == "for"));
assert!(!results.iter().any(|r| r.display_text == "class"));
}
#[test]
fn test_query_keywords_cxx_mode() {
let db = X86CompletionDatabase::new();
let results = db.query_keywords("class", true);
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text == "class"));
}
#[test]
fn test_query_directives() {
let db = X86CompletionDatabase::new();
let results = db.query_directives("#include");
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text == "#include"));
}
#[test]
fn test_query_builtin_macros() {
let db = X86CompletionDatabase::new();
let results = db.query_builtin_macros("__STDC__");
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text == "__STDC__"));
}
#[test]
fn test_keyword_list_includes_all_c_keywords() {
let db = X86CompletionDatabase::new();
let required = &[
"auto", "break", "case", "char", "const", "continue", "default", "do", "double",
"else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long",
"register", "restrict", "return", "short", "signed", "sizeof", "static", "struct",
"switch", "typedef", "union", "unsigned", "void", "volatile", "while",
];
for kw in required {
assert!(
db.c_keywords.iter().any(|k| k.display_text == *kw),
"Missing C keyword: {}",
kw
);
}
}
#[test]
fn test_x86_keyword_list_includes_builtins() {
let db = X86CompletionDatabase::new();
let required = &[
"__builtin_expect",
"__builtin_prefetch",
"__builtin_bswap32",
"__builtin_popcount",
"__builtin_clz",
"__builtin_unreachable",
];
for kw in required {
assert!(
db.x86_keywords.iter().any(|k| k.display_text == *kw),
"Missing X86 builtin: {}",
kw
);
}
}
#[test]
fn test_intrinsic_completion_new() {
let ic = X86IntrinsicCompletion::new();
assert!(!ic.is_empty());
assert!(ic.len() > 50);
}
#[test]
fn test_intrinsic_query_sse() {
let ic = X86IntrinsicCompletion::new();
let results = ic.query("_mm_add_ps");
assert!(!results.is_empty());
assert!(results
.iter()
.any(|r| r.filter_text.as_ref().unwrap() == "_mm_add_ps"));
}
#[test]
fn test_intrinsic_query_avx() {
let ic = X86IntrinsicCompletion::new();
let results = ic.query("_mm256_add_ps");
assert!(!results.is_empty());
}
#[test]
fn test_intrinsic_query_avx512() {
let ic = X86IntrinsicCompletion::new();
let results = ic.query("_mm512_add_ps");
assert!(!results.is_empty());
}
#[test]
fn test_intrinsic_query_ia32() {
let ic = X86IntrinsicCompletion::new();
let results = ic.query("__builtin_ia32_rdtsc");
assert!(!results.is_empty());
}
#[test]
fn test_intrinsic_query_fma() {
let ic = X86IntrinsicCompletion::new();
let results = ic.query("_mm_fmadd_ps");
assert!(!results.is_empty());
}
#[test]
fn test_intrinsic_get_detail() {
let ic = X86IntrinsicCompletion::new();
let detail = ic.get_detail("_mm_add_ps");
assert!(detail.is_some());
let d = detail.unwrap();
assert_eq!(d.return_type, "__m128");
assert_eq!(d.params.len(), 2);
assert_eq!(d.header, "xmmintrin.h");
}
#[test]
fn test_intrinsic_query_nonexistent() {
let ic = X86IntrinsicCompletion::new();
let results = ic.query("_mm_nonexistent_xyz");
assert!(results.is_empty());
}
#[test]
fn test_sse_intrinsics_exist() {
let ic = X86IntrinsicCompletion::new();
for name in &[
"_mm_load_ps",
"_mm_store_ps",
"_mm_add_ps",
"_mm_mul_ps",
"_mm_sqrt_ps",
"_mm_setzero_ps",
"_mm_set1_ps",
"_mm_shuffle_ps",
"_mm_cmpeq_ps",
"_mm_min_ps",
"_mm_max_ps",
] {
assert!(
ic.get_detail(name).is_some(),
"Missing SSE intrinsic: {}",
name
);
}
}
#[test]
fn test_sse2_intrinsics_exist() {
let ic = X86IntrinsicCompletion::new();
for name in &[
"_mm_add_epi32",
"_mm_and_si128",
"_mm_or_si128",
"_mm_xor_si128",
"_mm_setzero_si128",
"_mm_load_si128",
"_mm_store_si128",
"_mm_slli_epi32",
"_mm_srli_epi32",
"_mm_cmpeq_epi32",
] {
assert!(
ic.get_detail(name).is_some(),
"Missing SSE2 intrinsic: {}",
name
);
}
}
#[test]
fn test_avx2_intrinsics_exist() {
let ic = X86IntrinsicCompletion::new();
for name in &[
"_mm256_add_epi32",
"_mm256_mullo_epi32",
"_mm256_and_si256",
"_mm256_or_si256",
"_mm256_xor_si256",
"_mm256_setzero_si256",
] {
assert!(
ic.get_detail(name).is_some(),
"Missing AVX2 intrinsic: {}",
name
);
}
}
#[test]
fn test_type_completion_new() {
let tc = X86TypeCompletion::new();
assert!(tc.all_type_names().is_empty());
}
#[test]
fn test_register_struct_and_query() {
let mut tc = X86TypeCompletion::new();
tc.register_struct(
"Point",
&[
CompletionResult::keyword("x").with_priority(90),
CompletionResult::keyword("y").with_priority(90),
],
);
let members = tc.query_members("Point", "");
assert_eq!(members.len(), 2);
let names: Vec<&str> = members.iter().map(|m| m.display_text.as_str()).collect();
assert!(names.contains(&"x"));
assert!(names.contains(&"y"));
}
#[test]
fn test_query_members_with_prefix() {
let mut tc = X86TypeCompletion::new();
tc.register_struct(
"Rect",
&[
CompletionResult::keyword("width"),
CompletionResult::keyword("height"),
],
);
let members = tc.query_members("Rect", "w");
assert_eq!(members.len(), 1);
assert_eq!(members[0].display_text, "width");
}
#[test]
fn test_register_enum_and_query() {
let mut tc = X86TypeCompletion::new();
tc.register_enum(
"Color",
&[
CompletionResult::keyword("RED"),
CompletionResult::keyword("GREEN"),
CompletionResult::keyword("BLUE"),
],
);
let values = tc.query_enum_values("Color", "");
assert_eq!(values.len(), 3);
}
#[test]
fn test_query_scope() {
let mut tc = X86TypeCompletion::new();
tc.register_enum(
"Direction",
&[
CompletionResult::keyword("NORTH"),
CompletionResult::keyword("SOUTH"),
],
);
let results = tc.query_scope("Direction", "");
assert_eq!(results.len(), 2);
}
#[test]
fn test_all_type_names() {
let mut tc = X86TypeCompletion::new();
tc.register_struct("Foo", &[]);
tc.register_enum("Bar", &[]);
tc.register_class("Baz", &[]);
assert_eq!(tc.all_type_names().len(), 3);
}
#[test]
fn test_macro_completion_new() {
let mc = X86MacroCompletion::new(Vec::new());
assert_eq!(mc.macro_count(), 0);
}
#[test]
fn test_macro_define_and_query() {
let mut mc = X86MacroCompletion::new(Vec::new());
mc.define(
"MAX_SIZE",
MacroDef {
name: "MAX_SIZE".into(),
is_function_like: false,
params: vec![],
body: "1024".into(),
},
);
let results = mc.query("MAX");
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text == "MAX_SIZE"));
}
#[test]
fn test_macro_undefine() {
let mut mc = X86MacroCompletion::new(Vec::new());
mc.define(
"TEMP",
MacroDef {
name: "TEMP".into(),
is_function_like: false,
params: vec![],
body: "1".into(),
},
);
assert!(mc.is_defined("TEMP"));
mc.undefine("TEMP");
assert!(!mc.is_defined("TEMP"));
}
#[test]
fn test_macro_function_like() {
let mut mc = X86MacroCompletion::new(Vec::new());
mc.define(
"SQUARE",
MacroDef {
name: "SQUARE".into(),
is_function_like: true,
params: vec!["x".into()],
body: "((x) * (x))".into(),
},
);
let def = mc.get_definition("SQUARE");
assert!(def.is_some());
assert!(def.unwrap().is_function_like);
}
#[test]
fn test_header_completion_new() {
let hc = X86HeaderCompletion::new();
assert!(!hc.c_headers().is_empty());
assert!(!hc.cxx_headers().is_empty());
assert!(!hc.x86_headers().is_empty());
}
#[test]
fn test_query_system_include_exact() {
let hc = X86HeaderCompletion::new();
let results = hc.query_system_include("stdio.h");
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text == "stdio.h"));
}
#[test]
fn test_query_system_include_partial() {
let hc = X86HeaderCompletion::new();
let results = hc.query_system_include("std");
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text == "stdio.h"));
assert!(results.iter().any(|r| r.display_text == "stdlib.h"));
}
#[test]
fn test_x86_headers_include_immintrin() {
let hc = X86HeaderCompletion::new();
assert!(hc.x86_headers().iter().any(|h| h == "immintrin.h"));
assert!(hc.x86_headers().iter().any(|h| h == "xmmintrin.h"));
assert!(hc.x86_headers().iter().any(|h| h == "emmintrin.h"));
}
#[test]
fn test_call_tip_provider_new() {
let ctp = X86CallTipProvider::new();
assert_eq!(ctp.overload_count("printf"), 0);
}
#[test]
fn test_register_and_get_call_tip() {
let mut ctp = X86CallTipProvider::new();
ctp.register(
"foo",
"int",
vec![("int", "x", None), ("float", "y", Some("1.0f"))],
Some("Test function."),
);
let tip = ctp.get_call_tip("foo", 0);
assert!(tip.is_some());
let t = tip.unwrap();
assert_eq!(t.name, "foo");
assert!(t.signature.contains("int x, float y"));
assert_eq!(t.active_param, 0);
assert_eq!(t.overloads.len(), 1);
}
#[test]
fn test_standard_library_call_tips() {
let ctp = X86CallTipProvider::default();
assert!(ctp.get_call_tip("printf", 0).is_some());
assert!(ctp.get_call_tip("malloc", 0).is_some());
assert!(ctp.get_call_tip("memcpy", 0).is_some());
}
#[test]
fn test_snippet_generator_new() {
let sg = X86SnippetGenerator::new();
assert!(!sg.all().is_empty());
}
#[test]
fn test_snippet_query_for() {
let sg = X86SnippetGenerator::new();
let results = sg.query("for");
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text == "for"));
}
#[test]
fn test_snippet_query_if() {
let sg = X86SnippetGenerator::new();
let results = sg.query("if");
assert!(!results.is_empty());
}
#[test]
fn test_snippet_query_struct() {
let sg = X86SnippetGenerator::new();
let results = sg.query("struct");
assert!(!results.is_empty());
}
#[test]
fn test_snippets_are_marked() {
let sg = X86SnippetGenerator::new();
for s in sg.all() {
assert!(s.is_snippet);
}
}
#[test]
fn test_all_snippets_have_tab_stops() {
let sg = X86SnippetGenerator::new();
for s in sg.all() {
assert!(
s.insert_text.contains("${"),
"Snippet '{}' has no tab stops",
s.display_text
);
}
}
#[test]
fn test_code_completion_new() {
let cc = X86CodeCompletion::new(false);
assert!(!cc.cxx_mode);
assert_eq!(cc.max_results, 100);
assert!(cc.intrinsic_count() > 0);
}
#[test]
fn test_code_completion_cxx_mode() {
let cc = X86CodeCompletion::new(true);
assert!(cc.cxx_mode);
}
#[test]
fn test_complete_general_c() {
let cc = X86CodeCompletion::new(false);
let results = cc.complete(&CompletionContext::General, "for");
assert!(!results.is_empty());
assert!(results
.iter()
.any(|r| r.display_text == "for" && r.kind == CompletionKind::Keyword));
}
#[test]
fn test_complete_general_cxx() {
let cc = X86CodeCompletion::new(true);
let results = cc.complete(&CompletionContext::General, "class");
assert!(results.iter().any(|r| r.display_text == "class"));
}
#[test]
fn test_complete_directive() {
let cc = X86CodeCompletion::new(false);
let results = cc.complete(&CompletionContext::Directive, "#include");
assert!(!results.is_empty());
}
#[test]
fn test_complete_include_angle() {
let cc = X86CodeCompletion::new(false);
let results = cc.complete(
&CompletionContext::IncludeAngle {
partial: "stdio".into(),
},
"stdio",
);
assert!(!results.is_empty());
}
#[test]
fn test_complete_dot_access() {
let mut cc = X86CodeCompletion::new(false);
cc.register_struct(
"Vec3",
&[
CompletionResult::keyword("x"),
CompletionResult::keyword("y"),
CompletionResult::keyword("z"),
],
);
let results = cc.complete(
&CompletionContext::DotAccess {
receiver_type: Some("Vec3".into()),
},
"",
);
assert_eq!(results.len(), 3);
}
#[test]
fn test_complete_arrow_access() {
let mut cc = X86CodeCompletion::new(false);
cc.register_struct(
"Player",
&[
CompletionResult::keyword("health"),
CompletionResult::keyword("mana"),
],
);
let results = cc.complete(
&CompletionContext::ArrowAccess {
receiver_type: Some("Player".into()),
},
"h",
);
assert_eq!(results.len(), 1);
assert_eq!(results[0].display_text, "health");
}
#[test]
fn test_complete_scope_resolution() {
let mut cc = X86CodeCompletion::new(false);
cc.register_enum(
"Status",
&[
CompletionResult::keyword("OK"),
CompletionResult::keyword("ERROR"),
],
);
let results = cc.complete(
&CompletionContext::ScopeResolution {
scope_name: Some("Status".into()),
},
"",
);
assert_eq!(results.len(), 2);
}
#[test]
fn test_complete_type_name_context() {
let mut cc = X86CodeCompletion::new(false);
cc.register_struct("MyStruct", &[]);
let results = cc.complete(&CompletionContext::TypeName, "");
assert!(results.iter().any(|r| r.display_text == "int"));
assert!(results.iter().any(|r| r.display_text == "MyStruct"));
}
#[test]
fn test_complete_declaration_context() {
let cc = X86CodeCompletion::new(false);
let results = cc.complete(&CompletionContext::Declaration, "");
assert!(results.iter().any(|r| r.display_text == "int"));
assert!(results.iter().any(|r| r.display_text == "void"));
}
#[test]
fn test_call_tips_from_engine() {
let cc = X86CodeCompletion::new(false);
assert!(cc.get_call_tips("printf", 0).is_some());
}
#[test]
fn test_define_and_undefine_macro() {
let mut cc = X86CodeCompletion::new(false);
cc.define_macro(
"MY_MACRO",
MacroDef {
name: "MY_MACRO".into(),
is_function_like: false,
params: vec![],
body: "42".into(),
},
);
let results = cc.complete(&CompletionContext::General, "MY_MACRO");
assert!(results.iter().any(|r| r.display_text == "MY_MACRO"));
cc.undefine_macro("MY_MACRO");
let results2 = cc.complete(&CompletionContext::General, "MY_MACRO");
assert!(!results2.iter().any(|r| r.display_text == "MY_MACRO"));
}
#[test]
fn test_max_results_limit() {
let mut cc = X86CodeCompletion::new(false);
cc.set_max_results(10);
let results = cc.complete(&CompletionContext::General, "");
assert!(results.len() <= 10);
}
#[test]
fn test_no_duplicates_in_results() {
let cc = X86CodeCompletion::new(false);
let results = cc.complete(&CompletionContext::General, "");
let mut names = HashSet::new();
for r in &results {
assert!(
names.insert(r.display_text.clone()),
"Duplicate: {}",
r.display_text
);
}
}
#[test]
fn test_results_sorted_by_priority() {
let cc = X86CodeCompletion::new(false);
let results = cc.complete(&CompletionContext::General, "");
for window in results.windows(2) {
assert!(window[0].priority >= window[1].priority);
}
}
#[test]
fn test_levenshtein_identical() {
assert_eq!(levenshtein_distance("hello", "hello"), 0);
}
#[test]
fn test_levenshtein_empty() {
assert_eq!(levenshtein_distance("", "abc"), 3);
assert_eq!(levenshtein_distance("abc", ""), 3);
}
#[test]
fn test_levenshtein_substitution() {
assert_eq!(levenshtein_distance("kitten", "sitting"), 3);
}
#[test]
fn test_levenshtein_insertion() {
assert_eq!(levenshtein_distance("ab", "abc"), 1);
}
#[test]
fn test_levenshtein_deletion() {
assert_eq!(levenshtein_distance("abc", "ab"), 1);
}
#[test]
fn test_fuzzy_match_score_exact() {
assert_eq!(fuzzy_match_score("printf", "printf"), 100);
}
#[test]
fn test_fuzzy_match_score_prefix() {
assert!(fuzzy_match_score("printf", "pri") >= 80);
}
#[test]
fn test_fuzzy_match_score_substring() {
assert!(fuzzy_match_score("sprintf", "printf") >= 60);
}
#[test]
fn test_fuzzy_match_score_none() {
assert_eq!(fuzzy_match_score("abc", "xyz"), 0);
}
#[test]
fn test_complete_fuzzy() {
let cc = X86CodeCompletion::new(false);
let _ = cc.complete_fuzzy(&CompletionContext::General, "prntf", 2);
}
#[test]
fn test_complete_ranked() {
let cc = X86CodeCompletion::new(false);
let results = cc.complete_ranked(&CompletionContext::General, "int");
assert!(!results.is_empty());
for (_, score) in &results {
assert!(*score >= 0);
}
}
#[test]
fn test_complete_lsp() {
let cc = X86CodeCompletion::new(false);
let items = cc.complete_lsp(&CompletionContext::General, "for");
assert!(!items.is_empty());
for item in &items {
assert!(item.kind.is_some());
}
}
#[test]
fn test_cache_new() {
let cache = CompletionCache::new(100);
assert!(cache.is_empty());
}
#[test]
fn test_cache_put_and_get() {
let mut cache = CompletionCache::new(100);
cache.put(
&CompletionContext::General,
"test",
vec![CompletionResult::keyword("test")],
);
assert!(cache.get(&CompletionContext::General, "test").is_some());
}
#[test]
fn test_cache_miss() {
let mut cache = CompletionCache::new(100);
assert!(cache
.get(&CompletionContext::General, "nonexistent")
.is_none());
}
#[test]
fn test_cache_eviction() {
let mut cache = CompletionCache::new(2);
cache.put(
&CompletionContext::General,
"a",
vec![CompletionResult::keyword("a")],
);
cache.put(
&CompletionContext::General,
"b",
vec![CompletionResult::keyword("b")],
);
cache.put(
&CompletionContext::General,
"c",
vec![CompletionResult::keyword("c")],
);
assert!(cache.len() <= 2);
}
#[test]
fn test_cache_clear() {
let mut cache = CompletionCache::new(100);
cache.put(
&CompletionContext::General,
"x",
vec![CompletionResult::keyword("x")],
);
cache.clear();
assert!(cache.is_empty());
}
#[test]
fn test_abi_intrinsic_query() {
let abi = X86ABIIntrinsicCompletion::new();
assert!(!abi.query("__builtin_return_address").is_empty());
}
#[test]
fn test_atomic_completion_query() {
let ac = X86AtomicCompletion::new();
assert!(!ac.query("__atomic_load").is_empty());
assert!(!ac.query("__sync_fetch").is_empty());
}
#[test]
fn test_simd_type_completion_query() {
let stc = X86SIMDTypeCompletion::new();
let results = stc.query("__m128");
assert!(results.iter().any(|r| r.display_text == "__m128"));
}
#[test]
fn test_simd_type_all_known() {
let stc = X86SIMDTypeCompletion::new();
for name in &[
"__m64", "__m128", "__m128d", "__m128i", "__m256", "__m256d", "__m256i", "__m512",
"__m512d", "__m512i",
] {
assert!(
stc.all().iter().any(|r| r.display_text == *name),
"Missing SIMD type: {}",
name
);
}
}
#[test]
fn test_abstract_semantic_context_consistency() {
let cc = X86CodeCompletion::new(true);
let contexts = vec![
CompletionContext::DotAccess {
receiver_type: Some("Test".into()),
},
CompletionContext::ArrowAccess {
receiver_type: Some("Test".into()),
},
CompletionContext::ScopeResolution {
scope_name: Some("Test".into()),
},
CompletionContext::OpenParen {
callee: Some("func".into()),
},
CompletionContext::TypeName,
CompletionContext::Declaration,
CompletionContext::Directive,
CompletionContext::IncludeQuote {
partial: "test".into(),
},
CompletionContext::IncludeAngle {
partial: "test".into(),
},
CompletionContext::General,
CompletionContext::Statement,
CompletionContext::Return,
CompletionContext::Case,
CompletionContext::Goto,
];
for ctx in &contexts {
let _ = cc.complete(ctx, "");
}
}
#[test]
fn test_call_tip_overload_count() {
let ctp = X86CallTipProvider::default();
assert_eq!(ctp.overload_count("printf"), 1);
assert_eq!(ctp.overload_count("nonexistent_func"), 0);
}
#[test]
fn test_header_c_headers_nonempty() {
let hc = X86HeaderCompletion::new();
assert!(hc.c_headers().contains(&"stdio.h".to_string()));
assert!(hc.c_headers().contains(&"stdlib.h".to_string()));
assert!(hc.c_headers().contains(&"string.h".to_string()));
}
#[test]
fn test_all_builtin_macros_have_doc() {
let db = X86CompletionDatabase::new();
for m in &db.builtin_macros {
assert!(
m.documentation.is_some(),
"Builtin macro '{}' has no doc",
m.display_text
);
}
}
#[test]
fn test_completion_kind_all_variants() {
let variants = [
CompletionKind::Function,
CompletionKind::Variable,
CompletionKind::Type,
CompletionKind::Macro,
CompletionKind::Keyword,
CompletionKind::Directive,
CompletionKind::Field,
CompletionKind::EnumMember,
CompletionKind::Namespace,
CompletionKind::Snippet,
CompletionKind::File,
CompletionKind::Label,
CompletionKind::Concept,
CompletionKind::Operator,
CompletionKind::TypeParameter,
CompletionKind::Intrinsic,
CompletionKind::Module,
CompletionKind::Constant,
];
for v in &variants {
assert!(!v.icon().is_empty());
assert!(v.lsp_kind() > 0);
}
}
#[test]
fn test_intrinsic_priority_ordering() {
let ic = X86IntrinsicCompletion::new();
let all = ic.query("");
for w in all.windows(2) {
assert!(w[0].priority >= w[1].priority);
}
}
#[test]
fn test_score_exact_match_bonus() {
let r = CompletionResult::keyword("if");
assert!(X86CodeCompletion::score_completion(&r, "if") >= 150);
}
#[test]
fn test_score_deprecated_penalty() {
let r = CompletionResult::keyword("register").deprecated();
assert_eq!(X86CodeCompletion::score_completion(&r, "register"), 50);
}
#[test]
fn test_many_struct_registrations() {
let mut cc = X86CodeCompletion::new(false);
for i in 0..100 {
cc.register_struct(
&format!("Struct{}", i),
&[CompletionResult::keyword("field")],
);
}
assert_eq!(cc.type_completion.all_type_names().len(), 100);
}
#[test]
fn test_empty_prefix_matches_all() {
let cc = X86CodeCompletion::new(false);
let results = cc.complete(&CompletionContext::General, "");
assert!(!results.is_empty());
}
#[test]
fn test_large_prefix_no_results() {
let cc = X86CodeCompletion::new(false);
assert!(cc
.complete(&CompletionContext::General, "zzz_this_does_not_exist_xyz")
.is_empty());
}
#[test]
fn test_all_c_keywords_present() {
let db = X86CompletionDatabase::new();
let names: HashSet<String> = db
.c_keywords
.iter()
.map(|k| k.display_text.clone())
.collect();
let required = [
"auto", "break", "case", "char", "const", "continue", "default", "do", "double",
"else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long",
"register", "restrict", "return", "short", "signed", "sizeof", "static", "struct",
"switch", "typedef", "union", "unsigned", "void", "volatile", "while",
];
for kw in &required {
assert!(names.contains(*kw), "Missing: {}", kw);
}
}
#[test]
fn test_context_edge_cases() {
assert!(matches!(
CompletionContext::from_source_line("int main(void) { return foo.bar.baz.qux.", 39),
CompletionContext::DotAccess { .. }
));
assert_eq!(
CompletionContext::from_source_line(" #", 4),
CompletionContext::Directive
);
assert!(matches!(
CompletionContext::from_source_line("a->b.c->", 8),
CompletionContext::ArrowAccess { .. }
));
}
#[test]
fn test_intrinsic_detail_params() {
let ic = X86IntrinsicCompletion::new();
let d = ic.get_detail("_mm_add_ps").unwrap();
assert_eq!(d.params.len(), 2);
assert_eq!(d.params[0].0, "__m128");
assert_eq!(d.params[0].1, "a");
}
#[test]
fn test_intrinsic_detail_isa() {
let ic = X86IntrinsicCompletion::new();
assert_eq!(ic.get_detail("_mm_add_ps").unwrap().isa_extension, "SSE");
assert_eq!(ic.get_detail("_mm_add_pd").unwrap().isa_extension, "SSE2");
assert_eq!(ic.get_detail("_mm256_add_ps").unwrap().isa_extension, "AVX");
}
#[test]
fn test_header_completion_all_c_headers() {
let hc = X86HeaderCompletion::new();
for h in hc.c_headers() {
assert!(h.ends_with(".h"), "C header without .h: {}", h);
}
}
#[test]
fn test_call_tip_multiple_overloads() {
let mut ctp = X86CallTipProvider::new();
ctp.register("foo", "int", vec![("int", "x", None)], None);
ctp.register("foo", "double", vec![("double", "x", None)], None);
assert_eq!(ctp.overload_count("foo"), 2);
assert_eq!(ctp.get_call_tip("foo", 0).unwrap().overloads.len(), 2);
}
#[test]
fn test_complete_cxx_namespace() {
let mut cc = X86CodeCompletion::new(true);
cc.register_namespace(
"my_lib",
&[
CompletionResult::keyword("init"),
CompletionResult::keyword("shutdown"),
CompletionResult::keyword("Config"),
],
);
assert_eq!(
cc.complete(
&CompletionContext::ScopeResolution {
scope_name: Some("my_lib".into())
},
""
)
.len(),
3
);
}
#[test]
fn test_register_struct_twice_overwrites() {
let mut cc = X86CodeCompletion::new(false);
cc.register_struct("S", &[CompletionResult::keyword("a")]);
cc.register_struct("S", &[CompletionResult::keyword("b")]);
let results = cc.complete(
&CompletionContext::DotAccess {
receiver_type: Some("S".into()),
},
"",
);
assert_eq!(results.len(), 1);
assert_eq!(results[0].display_text, "b");
}
#[test]
fn test_set_cxx_mode_toggle() {
let mut cc = X86CodeCompletion::new(false);
assert!(!cc.cxx_mode);
cc.set_cxx_mode(true);
assert!(cc.cxx_mode);
cc.set_cxx_mode(false);
assert!(!cc.cxx_mode);
}
#[test]
fn test_large_number_of_completions() {
let cc = X86CodeCompletion::new(true);
assert!(cc.complete(&CompletionContext::General, "").len() >= 10);
}
#[test]
fn test_context_from_source_line_out_of_bounds() {
assert_eq!(
CompletionContext::from_source_line("short", 100),
CompletionContext::General
);
}
#[test]
fn test_cache_hit_rate_after_hits() {
let mut cache = CompletionCache::new(100);
cache.put(
&CompletionContext::General,
"x",
vec![CompletionResult::keyword("x")],
);
cache.get(&CompletionContext::General, "x");
cache.get(&CompletionContext::General, "y");
let rate = cache.hit_rate();
assert!(rate > 0.0 && rate < 100.0);
}
#[test]
fn test_completion_kind_all_values_unique() {
let kinds = vec![
CompletionKind::Function,
CompletionKind::Variable,
CompletionKind::Type,
CompletionKind::Macro,
CompletionKind::Keyword,
CompletionKind::Directive,
CompletionKind::Field,
CompletionKind::EnumMember,
CompletionKind::Namespace,
CompletionKind::Snippet,
CompletionKind::File,
CompletionKind::Label,
CompletionKind::Concept,
CompletionKind::Operator,
CompletionKind::TypeParameter,
CompletionKind::Intrinsic,
CompletionKind::Module,
CompletionKind::Constant,
];
let mut seen = HashSet::new();
for k in &kinds {
assert!(seen.insert(*k as u8), "Duplicate repr: {}", *k as u8);
}
}
#[test]
fn test_snippet_non_empty() {
let sg = X86SnippetGenerator::new();
for s in sg.all() {
assert!(!s.display_text.is_empty());
assert!(!s.insert_text.is_empty());
}
}
#[test]
fn test_levenshtein_cafe() {
assert_eq!(levenshtein_distance("cafe", "coffee"), 3);
}
#[test]
fn test_fuzzy_match_insensitive() {
assert_eq!(fuzzy_match_score("PRINTF", "printf"), 100);
}
}